C语言查漏补缺

1.C99中struct的柔性数组

// C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,
// 但结构中的柔性数组成员前面必须至少一个其他成员。
// 柔性数组成员允许结构中包含一个大小可变的数组。
// sizeof 返回的这种结构大小不包括柔性数组的内存。
typedef struct st_type
{
int i;
int a[]; // int a[0];
}type_a; 
// type_a 为 typede f定义的 结构体 st_type 的别名,方便使用
// 定义一个可变长的结构体,用 sizeof(type_a)得到的只有 4,就是 sizeof(i)=sizeof(int)。
// 给结构体分配内存
type_a *p = (type_a*)malloc(sizeof(type_a)+100*sizeof(int));
// 为结构体指针 p 分配了一块内存。用 p->a[n]就能简单地访问可变长元素。
// 我们再用 sizeof(*p)测试结构体的大小,发现仍然为 4。
// 在定义这个结构体的时候,模子的大小就已经确定不包含柔性数组的内存大小。
// 柔性数组只是编外人员,不占结构体的编制。
// 用 free 函数来释放内存:
// free(p);

2. 利用共用体测试机器大小端

int checkDuan( )
{
     union
     {
          int i;   // 4字节
          char ch; // 存放在 低地址
     }c;
     c.i = 127; //大端模式:高地址:0x007F 低地址:0x0000
                // 小端模式: 高地址:0x0000 低地址:0x007F

     printf("%x",c.ch);
return c.ch==127; 
}

3. typedef常见用法

1.	常规变量类型定义:typedef unsigned char uchar
描述:uchar等价于unsigned char类型定义
                       
2.	数组类型定义:typedef int array[2];(注:可理解为typedef int[] array)
     描述:array 等价于 int [2]定义; array a 声明等价于int a[2]声明
     typedef int array[M][N]; 
	描述: array等价于 int[M][N]定义; array a声明等价于int a[M][N]声明
3.	指针类型定义: typedef int * pointer;   
	描述: pointer等价于 int*定义; pointer p 声明等价于int* a声明
     typedef int *pointer[M]; 
	描述: pointer等价于 int*[M]定义; pointer p声明等价于int*a[M]声明
4.函数地址说明描述:int func(void);       
                    unsigned long funcAddr=(unsigned long)func;
                    funcAddr 的值是 func 函数的首地址
5.函数声明例如:typedef int func(void); 
                 func 等价于 int(void)类型函数
6.函数指针例如: typedef int (*func)(void) 
                 func等价于int (*)(void)类型  
                 func pf 等价于 int(*pf)(void)声明,pf是一个函数指针变量

4. 预处理


预处理名称    意 义  

#define      宏定义
#undef       撤销已定义过的宏名  
#include    使编译程序将另一源文件嵌入到带有#include 的源文件中  
#if         条件编译,#if 的一般含义是如果#if 后面的常量表达式为 true,    
            则编译它与#endif 之间的代码,否则跳过这些代码。  
#endif      命令 #endif 标识一个 #if 块的结束。   
#else       #else 命令的功能有点象 C 语言中的 else ,    
            #else 建立另一选择(在# if 失败的情况下)。   
#elif       #elif 命令意义与 else if 相同,   
            它形成一个 if else-if 阶梯状语句,可进行多种编译选择。   

#ifdef/#ifndef    用#ifdef 与 #ifndef 命令分别表示“如果有定义”及“如果无定义”,   
             是条件编译的另一种方法。    
#line         改变当前行数和文件名称,它们是在编译程序中预先定义的标识符,   
              命令的基本形式如下:   
              #line number["filename"]      
#error        编译程序时,只要遇到 #error 就会生成一个编译错误提示消息,并停止编译     
#pragma       为实现时定义的命令,它允许向编译程序传送各种指令
		例如,编译程序可能有一种选择,它支持对程序执行的跟踪。   
              可用#pragma语句指定一个跟踪选择。 

另外 ANSI 标准 C 还定义了如下几个宏:   
              _LINE_ 表示正在编译的文件的行号       
              _FILE_ 表示正在编译的文件的名字      
              _DATE_ 表示编译时刻的日期字符串,例如: "25 Dec 2007"    
              _TIME_ 表示编译时刻的时间字符串,例如: "12:30:55"    
              _STDC_ 判断该文件是不是定义成标准 C 程序  

5. #pragma编译

1. #pragma message("消息文本") 
     它能够在编译信息输出窗口中输出相应的信息,这对于源代码信息的控制是非常重要的。
     当编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。
     假设我们希望判断自己有没有在源代码的什么地方定义了_X86 这个宏可以用下面的方法:
     #ifdef _X86
     #pragma message(“_X86 macro activated!”)
     #endif

2. #pragma code_seg()
     另一个使用得比较多的 pragma 参数是 code_seg。
     格式如:
     #pragma code_seg( ["section-name"[,"section-class"] ] )
     它能够设置程序中函数代码存放的代码段,当我们开发驱动程序的时候就会使用到它。

3. #pragma once 编译一次
     比较常用,只要在头文件的最开始加入这条指令就能够保证头文件被编译一次, 
     但是考虑到兼容性并没有太多的使用它。

4. #pragma hdrstop
     #pragma hdrstop 表示预编译头文件到此为止,后面的头文件不进行预编译。 
     你可以用#pragma startup 指定编译优先级,
	如果使用了#pragma package(smart_init) ,
     BCB就会根据优先级的大小先后编译.

5. #pragma resource 载入资源
     #pragma resource "*.dfm"  表示把*.dfm 文件中的资源加入工程。 
     *.dfm 中包括窗体外观的定义。

6. #pragma warning 错误信息
     #pragma warning(disable:4507 34) // 不显示 4507 和 34 号警告信息
     #pragma warning(once:4385)       // 4385 号警告信息仅报告一次
     #pragma warning(error:164)       // 把 164 号警告信息作为一个错误。

     #pragma warning( push )保存所有警告信息的现有的警告状态。
     #pragma warning( push, n)保存所有警告信息的现有的警告状态,并且把全局警告等级设定为 n。
     #pragma warning( pop )向栈中弹出最后一个警告信息,在入栈和出栈之间所作的一切改动取消。

7. #pragma pack(用于指定内存对齐的方式(按指定的字节数进行对齐)) 和 内存对齐问题(降低访存消耗)
struct TestStruct1
{
     char c1;  // 1字节   数据结构(尤其是栈)应该尽可能地在自然边界上对齐。(大小为4的倍数)
     short s;  // 2字节
     char c2;  // 1字节
     int i;    // 4字节
}

|c1| - |     s |   编译器在默认情况下按照4字节对齐,即#pragma pack(4)
|c2| - | - | - |
| i            |
3*4 =12 字节

CPU对内存的读取不是连续的,而是分块读取的,块的大小只能是2^i字节数(i=0,1,2,3…)。
从CPU的读取性能和效率来考虑,若读取的数据未对齐,则需要两次总线周期来访问内存,因而效率会大打折扣。
某些硬件平台只能从规定的相对地址处读取特定类型的数据,否则产生硬件异常。

struct TestStruct2
{
     char c1;  // 1字节   
     char c2;  // 1字节
     short s;  // 2字节
     int i;    // 4字节
}

|c1|c2|s    |
|i          |
2*4 = 8字节内存


使用指令#pragma pack (n),编译器将按照 n 个字节对齐。
使用指令#pragma pack (),编译器将取消自定义字节对齐方式。
在#pragma pack (n)和#pragma pack ()之间的代码按 n 个字节对齐。


#pragma pack(8)
struct TestStruct4
{
     char a; // 1字节
     long b; // 4字节
};
struct TestStruct5
{
     char c;  // 1字节
     TestStruct4 d; 
     long long e;// 8字节
};
#pragma pack()
                         a    b
TestStruct4 的内存布局: 1***,1111,
                        c   TestStruct4.a TestStruct4.b   d
TestStruct5 的内存布局: 1***,   1***,      1111, ****, 11111111

6. 函数指针类型

void(*)() , 指向类型为 void (void)的函数的 函数指针
(void(*) ())0 ,将 0 强制转换为函数指针类型, 0 是一个地址,也就是说一个函数存在首地址为 0 的一段区域内。
(*(void(*) ())0),取 0 地址开始的一段内存里面的内容,其内容就是保存在首地址为 0 的一段区域内的函数。
(*(void(*) ())0)(), 这是函数调用
同理 :
(*(char**(*) (char **,char **))0) ( char **,char **);
char * (*pf)(char * p);   // 定义的是一个函数指针 pf, 指向一个类型为 char*(char*)的函数
char * (*pf[3])(char * p);// 定义一个 函数指针 数组, 数组名为 pf,数组内存储了 3 个指向函数的指针。
char * (*(*pf)[3])(char * p);// 定义一个指针,指向一个函数指针数组,该数组内存放3个 指向类型为char*(char*)的函数的函数指针。

7. 文档说明

/************************************************************************
* File Name : FN_FileName.c/ FN_FileName.h                      文件名
* Copyright : 2003-2008 XXXX Corporation,All Rights Reserved.   版权亦称“著作权”
* Module Name : Draw Engine/Display                             文件模块功能名称
*
* CPU : ARM7
* RTOS : Tron
*
* Create Date : 2008/10/01                                      创建日期
* Author/Corporation : WhoAmI/your company name                 作者
*
* Abstract Description : Place some description here.           文件描述信息
*
*-----------------------Revision History----------------------- 版本信息
* No Version Date Revised By Item Description
* 1 V0.95 08.05.18 WhoAmI abcdefghijklm WhatUDo
*
************************************************************************/

<内容来自网络,如有侵权,请立即联系本人,自当立即删除>

原文地址:https://www.cnblogs.com/bacmive/p/11315227.html