C语言中的条件编译

很久没更新了。。。因为工作之后比较忙,更多的学习记录会写在公司的wiki里

目前在公司主要做C/C++,原来了解不够深入,所以目前从基础开始简单记录一点东西。

1  简介

条件编译相关的预编译指令,包括  #define、#undef、#ifdef、#ifndef、#if、#elif、#else、#endif、defined。

#define            定义一个预处理宏
#undef            取消宏的定义

#if                   编译预处理中的条件命令,相当于C语法中的if语句
#ifdef              判断某个宏是否被定义,若已定义,执行随后的语句
#ifndef            与#ifdef相反,判断某个宏是否未被定义
#elif                若#if, #ifdef, #ifndef或前面的#elif条件不满足,则执行#elif之后的语句,相当于C语法中的else-if
#else              与#if, #ifdef, #ifndef对应, 若这些条件不满足,则执行#else之后的语句,相当于C语法中的else
#endif             #if, #ifdef, #ifndef这些条件命令的结束标志.
defined          与#if, #elif配合使用,判断某个宏是否被定义

2 应用场景

2.1 头文件包含

条件编译是根据实际定义宏(某类条件)进行代码静态编译的手段。可根据表达式的值或某个特定宏是否被定义来确定编译条件。最常见的条件编译是防止重复包含头文件的宏:

1 #ifndef ABCD_H
2 #define ABCD_H
3 
4 // ... some declaration codes
5 
6 #endif // #ifndef ABCD_H

这种场景使用最多。一般规范的编码习惯都会这样做。

2.2 基于系统变量的编译

#if SYSTEM == SYSV
    #define HDR "sysv.h"
#elif SYSTEM == BSD
    #define HDR "bsd.h"
#elif SYSTEM == MSDOS
    #define HDR "msdos.h"
#else
    #define HDR "default.h"
#endif

#include HDR

其中#ifdef #ifundef后面加符号(宏定义)。

0 恒 false,1 恒true。

在C语言中时常会用到#if 0,#if 1,#else,#endif语句,语句如下所示:

#if 0
    code1
#else
    code2
#endif

此时code1的语句被注释掉了,永远没有办法执行,而code2是被编译的;如果将#if 0变为#if 1,code1被编译,而code2永远没有办法被执行。

2.3 不同语言的编译

如果是C++调C库,例如有了一个C库文件,它的头文件是f.h

extern "C"
{
#include "f.h"
}

其中,extern "C" {}告诉编译器用C的规则去调用C函数。这里是在include头文件的外面包裹了extern "C" { },是告诉编译器以C语言的命名方式去加载这个符号。还有一种比较常见的方式是在头文件中进行编译声明,如下所示,这样的话,无论C还是C++直接正常include就可以使用了。

CAdd.h

#ifdef __cplusplus
extern "C" {
#endif

int cadd(int x, int y);

#ifdef __cplusplus
}
#endif

如上使用 __cplusplus宏的方法可以保证,这段程序既可以在C 中被编译,要可以在C++中被编译。

具体原因:

由于CPP支持多态性,也就是具有相同函数名的函数可以完成不同的功能,CPP通常是通过参数区分具体调用的是哪一个函数。在编译的时候,CPP编译器会将参数类型和函数名连接在一起,于是在程序编译成为目标文件以后,CPP编译器可以直接根据目标文件中的符号名将多个目标文件连接成一个目标文件或者可执行文件。但是在C语言中,由于完全没有多态性的概念,C编译器在编译时除了会在函数名前面添加一个下划线之外,什么也不会做(至少很多编译器都是这样干的)。由于这种的原因,当采用CPP与C混合编程的时候,就可能会出问题。

要明白为何使用extern"C",还得从cpp中对函数的重载处理开始说起。在c++中,为了支持重载机制,在编译生成的汇编码中,要对函数的名字进行一些处理,加入比如函数的返回类型等等.而在C中,只是简单的函数名字而已,不会加入其他的信息.也就是说:C++和C对产生的函数名字的处理是不一样的.

extern关键字,对该变量作“外部变量声明”,以扩展全局变量的作用域。

谨记:声明可以多次,但是定义只能有一次。函数的声明extern关键字是可有可无的,因为函数本身不加修饰的话就是extern的。

由于用 extern 引用外部变量,可以在引用的模块内修改其变量的值,因此,如果有多个文件同时要对应用的变量进行操作,而且可能会修改该变量,那就会影响其他模块的使用。因此,我们要慎重使用。

(1) 变量 
extern int a; //声明一个全局变量 
int a; //定义一个全局变量

extern int a = 0;//定义全局变量并给初值 
int a = 0; //定义全局变量并给初值 
        上面的四个只有第一个extern int a才是声明,其他的全是定义。 当你要引用一个全局变量时,你就要声明extern int a;这个时候extern不能省,否则就成定义了。

(2) 函数 
函数也有声明和定义,但由于函数的声明和定义是有区别的,函数的定义是有函数体的,所以函数的声明和定义都可以将extern省略掉,反正其他文件也是知道这个函数是在其他地方定义的。

#include <stdio.h>
int max(int x,int y);
int main(void)
{
    int result;
    /*外部变量声明*/
    extern int g_X;
    extern int g_Y;
    result = max(g_X,g_Y);
    printf("the max value is %d\n",result);
    return 0;
}
/*定义两个全局变量*/
int g_X = 10;
int g_Y = 20;
int max(int x, int y)
{
    return (x>y ? x : y);
}

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值