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 * ************************************************************************/
<内容来自网络,如有侵权,请立即联系本人,自当立即删除>