预处理指令

预处理指令

​ 程序员所编写的c代码并不能直接被编译,而是需要一段程序预先翻译成标准的c代码,负责处理的程序就叫预处理器,翻译的过程就叫做预处理,被翻译的代码就叫做预处理指令,所有预处理指令都是以#开头

gcc -E file.c 把预处理结果显示在屏幕上

gcc E file.c -o file.i 把预处理结果输出到文件上

include 把头文件插入当前文件中

​ #include<> 从系统指定的路径下查找头文件,并插入当前文件中。

​ #include"" 先从当前路径下查找头文件,如果没有再从系统指定路径下查找头文件,然后再插入当前文件中。

define 宏定义指令

​ 定义号宏常量

​ #define 宏名 (字面值)

​ 注意:末尾不要加分号

​ 作用:用标识符来替代字面值数据,从而提高代码的可读性,可扩展性。

​ 代码在预处理时所使用的宏名会被替换成字面值。

​ #define 宏名(a,b,c) (a+b+c)

​ 不是真正的函数,而是在使用了带参数的宏,预处理时使用了带参宏的位置替换成宏名后面的语句,所提供的的参数也会被替换到语句中的位置。

优点:

  1. 不是真正的函数调用,没有参数传递过程,也没有返回值
  2. 不限制参数类型,任何类型都可以使用,代码的通用性强

缺点:

  1. 没有类型检查,安全性低
  2. 过多使用会造成代码冗SW余,导致代码段增大,浪费内存。
  3. 可能会有二义性(多加点括号)

定义宏函数要注意的问题:

  1. 给每个参数加一个小括号,避免产生二义性
  2. 使用小括号、大括号包含整个宏函数代码,进行保护
  3. 宏函数不能换行可以使用续行符 \ 来分行一下,但是还是一行
  4. 宏函数参数不要使用自变运算符。

练习

​ 定义一个交换两个变量的宏函数,要任何类型的变量都可以使用

the first way

#define swap(a,b,type) {            \
	            type t=a;			\
	            a=b;				\
	            b=t;				\
            }

the second way

#define swap(a,b) {typeof(a) t=a; a=b; b=t;}

在编译时也可以定义宏:

gcc -D DEBUG

预定义好的宏:

        __func__   获取函数名
        __FILE__   获取文件名
        __LINE__   获取当前行号
        __DATE__   获取当前日期
        __TIME__   获取当前时间
        __cplusplus 变量只在c++中编译,判断是不是在c++环境中

删除宏

undef 宏名

条件判断

if , #ifdef , #ifndef , #else , #elif , #endif

头文件卫士

​ #ifndef、#define、#endif 防止头文件被重复包含

代码注释

//单行注释,使用麻烦,早期的编译器不支持

/*不能嵌套使用 */ 不能嵌套使用

if 0|1

​ 适合注释大段代码

endif

判断代码的编译、运行的环境:

    #ifdef _cplusplus
 ​            printf("C++编译器")
 ​        #else
 ​            printf("C编译器")
 ​        #endif



    #if defined(__APPLE__)
        puts("我用的是mac os");
    #elif defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
        puts("我用的是windows os");
    #elif defined(__linux__)
        puts("我用的是linux os");
    #endif 

用于调试程序的DEBUG函数:

#ifdef  DEBUG
#define debug(fmt,...)\
{\
     printf("File:%s Line:%u Func:%s Info:",__FILE__,__LINE__,__func__);\
     printf("\033[01;34m");\
     printf("fmt,##__VA_ARGS__");\
     printf("\033[00m\n");\
}
#else
#define debug(fmt,...) if(0)
#endif

其他预处理指令:

error "字符串" 产生一条件编译错误信息(不会生成可执行文件),与#if系列指令配合使用才有意义。

#warning "字符串" 产生一条件编译警告信息(正常生成可执行文件),要与#if系列指令配合使用才有意义。
#line line_number "filename" 设置代码的行号和文件名。
#pragma 可以让编译器执行某些事. 因为#pragma命令的执行很特殊,不同的编译器使用有所不同。
    #pragma pack(n) 用于修改内存对齐、补齐最大字节数 n等于2的n次方才有意义,n<默认最大字节数。
    #pragma GCC poison <标识符> 把某个标识符定义为毒药,禁止使用,一般用于禁用goto语句。
posted @ 2021-07-16 16:59  de06  阅读(151)  评论(0编辑  收藏  举报