C语言基础---条件编译

本文介绍了C语言中的条件编译,包括预处理指令#if、#ifdef、#ifndef等,以及头文件卫士的使用。讲解了如何通过预处理指令进行版本、环境判断,如编译器位数、操作系统类型。还提到了宏函数的变长参数、do while与宏函数的结合使用,以及多文件编程时的注意事项,如头文件的编写规范和防止头文件递归包含的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

条件编译:

    条件语句(if、switch、for、while、do while)会根据条件选择执行哪些代码,预处理器根据条件选择哪些代码参与下一步的编译。

    负责条件编译的预处理指令有:

        #if/#ifdef/#ifndef/#else if#else/#endif

    头文件卫士:

        #ifndef FILE_H // 判断FILE_H宏是否正在,不存在则条件为真

        #define FILE_H // 定义FILE_H宏

        #endif//FILE_H // #ifndef的结尾

        这种固定写法,一般在头文件中使用,它能防止头文件被重复包含。

    注释代码:

        // 只能注释单行代码,早期的编译器不支持该用

        /* 多行注释,但不能嵌套 */

        #if 0|1

        可注释大块代码,可以嵌套

        #endif

    版本、环境判断:

        编译器的位数:

            #if __WORDSIZE == 64

            #endif

        操作系统:

            #if __linux__

            #endif

            #if __WIN32 | __WIN32__ | __WIN64__

            #endif

        判断gcc还是g++:

            #if __cplusplus

            #else

       

            #endif

不常用的预处理指令:

    #line <常整数> 设置代码的行号,目前没有发现它有什么用

    #error "在预处理阶段提示错误信息",一旦预处理遇到它,将不再继续编译,它不能单独使用必须与条件判断系列语句配合使用

    #warning "在预处理阶段提示警告信息" 不能建议单独使用,最好与条件判断系列语句配合使用。

    #pragma GCC poison <标识符> 把标识符设置病毒,禁止在代码中使用

    每个系统在进入对齐和补齐都有一个最大对齐和补齐字节数n,也就是超出n字节按n字节计算,例如:linux32系统n=4,windows32 n=8

    #pragma pack(n)  设置最大对齐和补齐字节数

        设置要求:

            1、n < 系统默认的最大对齐、补齐字节数

            2、n必须是2的x次方,也就是必须是1、2、4、8、16这一类的整数

    宏函数的变长参数:

        #define func(...) __VA_ARGS__

        注意:这种用法必须配合,printf/fprintf/sprintf系列支持变长参数的函数使用。

do while与宏函数:

    如果宏函数有多行语句,并且被大括号包包含,在调用宏函数时,可以不写分号。

    为了保护语法的一致性,可以使用do while语句包含宏函数的代码。

    do{

    }while(0)

在编译时定义宏:

    gcc xxx.c -D ARR_LEN=3

    -D ARR_LEN=3 <=> #define ARR_LEN 3

DEUBG宏:

    专门用于调试程序的宏函数,这种宏函数在程序测试、调试、试运行阶段执行,在程序正式上线阶段不执行。

    一些操作提示,如:xxx操作成功,xxx操作失败,分配内存的记录、释放内存的记录,这类型消息开发人员、测试人员需要看到,但用户不需要看到。

    void* _my_malloc(size_t size,const char* file,const char* func,size_t line)

    {

        void* ptr = malloc(size);

        printf("%s %s %u malloc %p  %u byte\n",file,func,line,ptr,size);

        return ptr;

    }

    #ifdef DEBUG

    # define my_malloc(size) _my_malloc(size,__FILE__,__func__,__LINE__)

    #else

    # define my_malloc(size) malloc(size)

    #endif//DEBUG

    #ifdef DEBUG

    # define my_free(ptr) do{                                        \

        free(ptr);                                                   \

        printf("%s %s %u free %p\n",__FILE__,__func__,__LINE__,ptr); \

    }while(0)

    #else

    # define my_free(ptr) free(ptr)

    #endif//DEBUG

    #ifdef DEBUG

    # define debug(...) do{\

        printf("file:%s func:%s line:%d:",__FILE__,__func__,__LINE__); \

        printf("\33[01;32m");\

        printf(__VA_ARGS__);\

        printf("\33[00m");\

    }while(0)

    #else

    # define debug(...) do{}while(0)

    #endif//DEBUG

多文件编程:

    当程序的业务逻辑越来越复杂,代码量越来越多,就需要多人组成团队协同开发,那么就必须把任务拆分成若干个文件。

    一般的拆分方案:

        main.c 只当作程序的入口,不实现业务逻辑代码。

      

        用于实现程序具体的业务逻辑代码

        模块名.h 用说明.c文件中有哪些函数、全局变量,也就是函数声明、全局变量声明。

        模块名.c 具体的函数实现,全局变量定义。

        项目中常用的、通用的工具,宏函数、函数

        tools.h

        tools.c

      

        只用于类型设计

        type.h 结构体、联合、枚举、宏常量、宏函数

   

    头文件中可以写什么:

        由于头文件可能会被若干个.c文件包含,那么每包含一次.c文件中就会有一份头文件的内容,所以头文件中的内容必须可重复,因此我们只适合在头文件中实现以下内容:

        1、头文件卫士

        2、#include 语句

        3、宏常量、宏函数

        4、全局变量的声明(变量的声明可以有多份,但定义只能有一份)。

        5、函数声明

        6、结构、联合、枚举复合的类型设计

        7、类型重定义

    头文件互相包含、递归包含:

        注意:头文件卫士只能解决重复包含的问题,但无法解决相互包含、递归包含的问题。

        互相包含:

        a.h #include "b.h"

        b.h #include "a.h"

        递归包含:

        a.h #include "b.h"

        b.h #include "c.h"

        c.h #include "a.h"

        解决这种问题的文件,再设计一个.h文件,把他们共用的内存,实现在新的.h文件中,被他们共同包含即可。

    多文件编译过程:

        1、gcc xxx.h 检查头文件是否有语法错误,如果没有语法错误会生成xxx.h.gch,检查完毕后该文件要立即删除。

        2、gcc -c xxx.c 把.c文件编译成二进制目标文件

        3、gcc *.o 把所有目标文件合成可执行文件,也可以使用-o 设置可执行文件的名字。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值