预处理详解,关于#define 宏 ##和#

预处理详解

预定义符号
__FILE__
//进行编译的源文件
__LINE__
//文件当前的行号
__DATE__
//文件被编译的日期
__TIME__
//文件被编译的时间
__STDC__
//如果编译器遵循ANSIC,其值为1.否则未定义
这些预定义符号都是语言内置的。举个栗子:

printf("file:%s Tine:%\n",__FILE___LINE__);

#define

#define定义标识符
语法:
#define name stuff

//写日志文件
inti=0;
int arr[10] ={0};
FILE* pf = fopen("log.txt","w");
for (i = 0; i < 10; i++)
{
arr[i] =i;
fprintf(pf, "file:%s line:%d date:%s time:%s i=%d\n",
_FILE_,_LINE_,_DATE____TIME_i);
fclose(pf);
}
pf =NULL;
for (i = 0; i < 10; i++)
{
printf("%d ",arr[i]);
}
return 0;
}

举个栗子:
#define MAX 1000
#define reg register

//为register这个关键字,创建一个简短的名字
#define do_forever for(::)
//用更形象的花号来替换一种实现
#define cAsE break;case
//在写case语句的时候自动把 break写上。
//如果定义的 stuff过长,可以分成几行写,除了最后一行外,每行的后面都加一个反斜杠(续行符)。

#define DEBUG PRINT printf("file:%s\tline:%d\t\date:%s\ttime:%s\n"。
_FILE_LINE__DATE__TIME_)

在define定义标识符的时候,要不要在最后加上;?
比如:
#define MAX 1000;
#deFine MAX 1000
建议不要加上;这样容易导致问题。比如下面的场景:

if(condition)
max =MAX;
else
max-0;

这里会出现语法错误。

#define定义宏

#define机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(definemacro)_
下面是宏的申明方式:
#define name parament1ist)stuff其中的paramentist是一个由逗号隔开的符号表,它们可能出现在
stuff中。
注意:参数列表的左括号必须与name紧邻。如果两者之间有任何空白存在,参数列表就会被解释为stuff的一部分。
如:
#define SQUARE (X)X*X
这个宏接收一个参数x如果在上述声明之后,你把SQUARE(5);置于程序中,预处理器就会用下面这个表达式替换上面的表达式:

s*s;

printf(%\n”(a+1)*(a+1));

这里还有一个宏定义:
#define DOUBLE (x(x)+(x)
定义中我们使用了括号,想避免之前的问题,但是这个宏可能会出现新的错误。
inta=5;
printf(%d\n"10*DOUBLE(a));
这将打印什么值呢?
warning:看上去,好像打印100,但事实上打印的是55我们发现替换之后:
printf(%d\n".10(5)+(5));
乘法运算先于宏定义的加法,所以出现了

inta=5;
printf('%d\n”10*DOUBLE(a));
这将打印什么值呢?
warning:看上去,好像打印100,但事实上打印的是55.我们发现替换之后
printf(%d\n10*(5)+(5));
乘法运算先于宏定义的加法,所以出现了
55.
这个问题,的解决办法是在宏定义表达式两边加上一对括号就可以了。
#defineDOUBLE(x)((x)+(x))
提示:
所以用对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻近操作符之间不可预料的相互作用.

#define替换规则

在程序中扩展#define定义符号和宏时,需要涉及几个步骤。
1在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先被替换,
2.替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。
3.最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上述处理过程。
注意:
1.宏参数和#define定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归。
2.当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。

#和##

如何把参数插入到字符串中?
首先我们看看这样的代码:
char*p="he1o""bit\n";
printf("hello"" bit\n");
printf(“%s",p);

这里输出的是不是
hello bit ?
答案是确定的:是。
我们发现字符串是有自动连接的特点的。
1.那我们是不是可以写这样的代码?:
#define PRINT(FORMATVALUE)\
printf("the value is"FORMAT"\n”VALUE);
-..
PRINT("%d",10);
这里只有当字符串作为宏参数的时候才可以把字符串放在字符串中,

1另外一个技巧是:使用#,把一个宏参数变成对应的字符串。比如:
inti=10:
#define PRINT(FORMATVALUE)\
printf("the value of " #VALUE"is"FORMAT"\n",VALUE);
PRINT(%d"i+3);//产生了什么效果?
代码中的#VALUE会预处理器处理为:
"VALUE",最终的输出的结果应该是:
the value of i+3 is13

##的作用

#可以把位于它两边的符号合成一个符号。它分许宏定义从分离的文本片段创建标识得。
#define ADD_TO_SUM(numvaTue)
Sum##num+=value;
...
ADD_TO_SUM(510)://作用是:给sum5增加10.
注:这样的连接必须产生一个合法的标识符,否则其结果就是未定义的。

带副作用的宏参数

当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险,导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果。例如:
x+1;//不带副作用
x++://带有副作用
MAX宏可以证明具有副作用的参数所引起的问题。

宏和函数对比

宏通常被应用于执行简单的运算。比如在两个数中找出较大的一个。
#defineMAX(a,b)((a)>(b)?(a):(b))
那为什么不用函数来完成这个任务?原因有二:
1.用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序
的规模和速度方面更胜一筹。
2.更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之这个宏怎可
以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的。

当然和宏相比函数也有劣势的地方:
1.每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序的长度。
2.宏是没法调试的。
3.宏由于类型无关,也就不够严谨。
4.宏可能会带来运算符优先级的问题,导致程容易出现错。

猜你喜欢

转载自blog.csdn.net/2301_77479336/article/details/130216409