C语言预处理指令
define
语法Linux编译时指定宏的值及宏删除已有的宏C语言允许多参数的宏及宏函数
宏函数需要注意的事项参数宏创建字符串预处理粘合剂 linewarningerrorpragma条件编译
语法格式头文件卫士
C语言中带#的为预处理指令Linux中 (gcc -E xxx.c) 进行预处理Linux中(gcc -D 宏 = 值 xxx.c)定义宏 define
#define MACRO_NAME CONTENT //MACRO_NAME 宏名称 一般用于大写 区别于变量 //ConTENT 要替换的内容 可以是常量 变量 表达式 语句 #define MACRO_NAME //也可以只定义宏 不加替换的东西语法
#前后可以有空格宏名称不能有空格 会把define后面第一个标识符当作宏名称 宏名称后面的内容当作要替换的内容
#define T X Z T;//T会被替换成 X Z
宏定义只是简单的替换宏定义如果需要拆行需要宏定义不是说明或语句,不需要分号作为结束标识 如果在宏定义有;也会视为替换内容的一部分。预处理其实就是宏展开的一部分。宏定义允许嵌套,在展开时不会凭空添加()简单层层替换而已。
#define MULTI1(a,b) ((a)*(b)) //必须每个地方都加上括号 //otherwise #define MULTI2(a,b) (a*b) int a=2,b=3; int c = MULTI1(a+1,b+2); int d = MULTI2(a+1,b+2); printf("c = %dn",c); // a+1*b+2 printf("d = %dn",d); // (a+1)*(b+2)
define与typedef区别
define直接替换,然而typedef是别名
下面一个例子你就懂了
#define IT int * typedef int *TT; int main(){ IT a,b;// int *a,b; //b不是int*类型而是int类型 TT m,n;// int *m,*n; unsigned IT x; //allow unsigned TT y; //compile error return 0; }
define与const区别
#define定义的常量称为明示常量
const定义的常量一般表示只读,其实不是真正的常量
同样举个栗子
#define DN 10 const int CN = 20; static int arr[DN]; static int brr[CN];// compile error int crr[CN]; // compile error 在全局区无法确定数组大小,全局区严格控制内存大小,不允许变长。 const int ci = DN*20; const int cc = CN*20; int main(){ int drr[CN];//stack区 在栈区允许边长数组 static int err[CN]; //一样也是全局区 static int frr[CN]; //真正的常量是可以的 return 0; }Linux编译时指定宏的值及宏
gcc -D 宏 = 值 xxx.c 删除已有的宏
#undef C语言允许多参数的宏及宏函数
#define MACRO_NAME(ARGLIST) CONTENT //MACRO_NAME 宏名称 //ARGLIST 宏参数列表 不需要类型,只需要标识符即可,多个参数用逗号隔开, 支持...(多参数) //ConTENT //宏所需要替换的语句内容
宏函数需要注意的事项
宏函数名和()之间不能存在空格,不然在空格前面的部分就会被认定为宏名称。带参数的宏不会为形参分配内存空间,因此不必指明参数的类型宏函数的参数允许类型 va_arg(ap,type)
#define T(type,b) type c = b int main(){ T(int,10); //int c = 10; return 0; }
参数宏创建字符串
#define STR(arg) #arg int main(){ printf("第一个C语言程序:"STR(Hello world!)); return 0; }
预处理粘合剂
可以看我之前的内容里面有详细的案例(在此就不赘述了) line
#line n filename 指定行号 warning
让预处理(编译)产生警告 #warning error
#error 让预处理(编译)产生错误 直接中断编译 pragma
在预处理阶段会被保留下来,用于设置编译器属性
#pragma GCC dependency <文件> / "文件" //表示当前文件依赖于 ""/<> 中文件 如果 ""/<>中文件比当前文件更新,则编译会报警告 依赖: 如果一个文件依赖于另外一个文件,文件新旧:更新的文件意味着修改 #pragma GCC poison 标识 //对标识进行投毒 标识将无法在代码中使用 #pragma pack(n) //n取1,2,4,8 改变对齐补齐默认字节条件编译
在预处理时,会根据条件进行选择性的编译代码 (只有一部分代码会被编译)与分支语句不同,分支(if switch)会把所有分支都编译到代码中,不管分支有没有执行条件编译,只会选择其一个分支进行编译,所以生成的执行文件会比较小 运行效率比较高分支语句,会把所有分支进行编译到可执行文件中,执行文件比较大,在运行时进行判断执行具体分支 语法格式
#ifdef && #ifndef #else #endif
#ifdef MACRO_NAME //有定义运行,被编译 #endif #ifndef MACRO_NAME //没定义运行 #else //有定义 #endif
#if #elif
选择其一其他预处理时删除。 #if(条件1) #elif(条件2) #else #endif头文件卫士
所有C语言头文件都应该置于头文件卫士中。
#ifndef MACRO_H__ //如果未定义 进行定义 防止多次定义读取 #define MACRO_H__ #endif //MACRO_H__
第一次在程序中导入该头文件时,MACRO_H__宏是没有定义过的,所以第一次会把头文件中的内容导入到代码中,当后面再#include该头文件时,则发现宏已经被定义过了,所以不会再导入头文件的内容作用: 防止头文件的内容重复导入 重复导入可能引发重定义的错误
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)