c 语言条件编译关键字,1-C语言#define关键字,条件编译及预定义符号详解

本文详细介绍了C语言预处理的概念及应用,包括预定义符号、#define关键字的使用方法、宏定义及其注意事项、条件编译的多种形式以及与其他语言特性如函数的对比。通过实例帮助读者理解并掌握预处理技巧。

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

一.预定义符号

C标准定义了如下五个预处理符号

__FILE__//进行编译的源文件名称

__LINE__//文件当前行号

__DATE__//文件被编译的日期

__TIME__//文件被编译的时间

__STDC__//如果编译器遵循ANSI C,值为1,否则未定义

在文件输入输出以及输出日志等场合下我们会用到这些预处理符号,比如

#include

#include

#define LOG fprintf(pf,"%d %d %d %d\n",\

__FILE__,__LINE__,__DATE__,__TIME__,__STDC__)

int main()

{

int i = 0;

FILE* pf = fopen("log.txt","w");w

if(pf == NULL)

{

printf("open failure!\n");

exit(EXIT_FAILURE);

}

for(i = 0; i < 5; i++)

{

LOG;

}

fclose(pf);

return 0;

}

\+回车 : 续行符,转义字符,后面不能加任何除回车之外的字符,否则会报错

二.#define关键字

#define有两个作用,一个是定义标识符,第二个是定义宏

1.定义标识符

//#define name stuff

#define MYINT int

//typedef stuff name

typedef int MYINT;

不要在define定义的标识符里加分号

2.定义宏

#define机制包括一个规定,允许把参数替换到文本中,这种实现通常叫做宏或定义宏

//#define name(parament-list) stuff

#define MAX ((a)>(b)?(a)(b))

int a = MAX(11+2,11-2);//int a = ((11+2)>(11-2)?(11+2):(11-2));

宏定义永远不要吝啬括号,防止因为优先级的问题导致出现不可思议的后果

宏不能实现递归

宏只文本替换,并不简化计算

字符串中的内容不会发生宏替换

#define X 100

printf("X");//不会宏替换#和##

3.#和 ##

编译器会自动就两个相邻字符串自动连接成一个

#:把参数插入到字符串中

#a -> “a”

#define PRINT(x,format)\

printf("the value of "#a" is "#format"\n",x)

//printf("the value of ""x"" is""format""\n",x)

int a = 10;

PRINT(x,"%d");

##可以把位于它两边的符号拼成一个符号

#define CAT(x,y) ((x)##(y))

int num5 = 10;

CAT(num,5);//=num5

4.宏和函数对比

①宏没有类型检查

没有类型检查是宏的一大特点(但同时也是不安全的隐患),可以完成很多函数不可能做到的功能

#define MALLOC(n,type)\

(type*)malloc(n*sizeof(type))

②宏没有函数的调用和返回等额外开销,效率更高,

但是当逻辑复杂并且代码量巨大时,调用和返回的开销和运算的时间相比微乎其微,可以省略

③宏单纯只是文本替换,不能进行调试,很致命

④宏可能会使代码长度增长

⑤函数的参数如果是一个表达式,会计算出表达式的结果传入参数

宏的参数如果是一个表达式,只会文本替换,不会进行计算

总结:各有千秋,小代码量使用宏,大代码量使用函数,C++中摈弃宏这一概念,使用内联,基于优缺点,最好不要使用宏

5.带有副作用的宏参数

int a = 10;int b = 0;

b = a+1;

b = a++;//带有副作用的表达式,使a发生改变

不要给宏参数传入带有副作用的参数

6.命名约定

宏:全部大写

函数: 不全部大写

例外

//getchar()由库函数实现还是由宏实现是编译器决定的

#define getchar() getc()

#undef name //取消宏标识符name的定义

三.条件编译

1.如果定义了DEBUG,语句执行,反之,不执行

#define __DEBUG__ 1

#ifdef __DEBUG__

语句;

#endif

2.条件编译

#if 常量表达式(为真编译,为假,不编译)

语句;

#endif

3.多分支条件编译

#if 常量表达式

语句;

#elif 常量表达式

语句;

#elif 常量表达式

语句;

#endif

3.判断是否被定义

#ifndef __DEBUG__

//==>#if !defined(__DEBUG__)

#ifdef __DEBUG__

//==>#if defined(__DEBUG__)

4.嵌套指令

预处理指令可以进行嵌套

pragma onec //新式防止头文件被多次引用

//繁琐

#ifndef __TEST_H__

#define __TEST_H__

#endif //__TEST_H__

四.其它

1.头文件的包含

#include

//直接去库目录下查找

#include "filename"

//先查找当前工作目录下查找,然后去库目录查找

2.#error “…”

遇到#error便会产生一个编译错误

3.strcpy();

源字符串必须以’/0’结束,返回目标字符串地址

且这个函数不管目标空间是否放得下返回的目标字符串

4.assert(条件语句)

善用断言,头文件为

5.链式反应

这次函数的返回值可以作为下一个函数的参数,达到链式反应的效果

printf(“%d\n”,strlen(strcpy(p,”hello world!”)));

6.常见错误:

编译型错误

直接看编译器错误提示信息即可

链接型错误

函数名,变量名写错,库文件使用错误(第三方库)

运行时错误

相关内容可参考

《C语言深度解剖》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值