C语言编程常见问题解答之编译预处理

C语言编程常见问题解答之编译预处理,第1张

C语言编程常见问题解答之编译预处理,第2张

本章主要讨论与预处理相关的问题。在编译器正常编译程序之前,需要先运行预处理器。可能你之前没见过这个程序,因为一般都是在幕后运行,程序员看不到。但是,这个程序非常有用。
预处理器会根据源代码中的预处理指令修改你的程序。预处理指令(比如#define)为预处理器提供了具体的指令,告诉它如何修改你的源代码。预处理器读取所有包含的文件和要编译的源代码,并在处理后生成源代码的预处理版本。在此版本中,宏和常量标识符已被相应的代码和值所取代。如果源代码中包含条件预处理指令(如#if),预处理器会先判断条件,然后再相应修改源代码。
预处理器有很多非常有用的功能,比如宏定义、条件编译、在源代码中插入预定义的环境变量、打开或关闭编译选项等等。对于职业程序员来说,深入了解预处理器的各种特性是创建快速高效程序的关键之一。
阅读本章时,请记住本章采用的一些技术(以及提到的一些常见陷阱),以便更好地利用预处理器的各种功能。
5.1什么是宏?如何使用宏?
Macro是一个预处理指令,它提供了一种替换源代码中字符串的机制。宏由“#define”语句定义。下面是一个宏定义的例子:
#定义版本—标记“1.02”

上面例子中定义的这种形式的宏通常被称为标识符。在上面的例子中,标识符VERSION_STAMP代表字符串“1.02”——在编译预处理期间,源代码中的每个VERSION_STAMP标识符都将被替换为字符串“1.02”。
下面是另一个宏定义的例子:
#define CUBE(x)((x),(x)*(x))
上面的例子中定义了一个名为CUBE的宏,它有一个参数x,CUBE有自己的宏体,即((x)*(x)*(x))-源代码中的每个CUBE(x)宏在预编译时都会被替换为((x)*(x)*(x))。
使用宏有以下优点:
(1)输入源代码时,可以省略很多打字操作。
(2)因为宏只需要定义一次,但是可以多次使用,所以使用宏可以增强程序的可读性和可靠性。
(3)使用宏没有额外的开销,因为宏表示的代码只在宏出现的地方展开,所以不会引起程序跳转。
(4)宏的参数对类型不敏感,不必考虑将哪种数据类型传递给宏。
需要注意的是,宏名和参数周围的括号之间绝对不能有空大小写。另外,为了避免翻译宏时的歧义,宏体也应该用括号括起来。例如,像下面这样定义多维数据集宏是不正确的:
denne CUBE(x) x * x * x
请注意传递给宏的参数。例如,一个常见的错误是将自增变量传递给宏。请看下面的例子:
# include
# include
void main(void)
{
int x,y;
x = 5;
y = CUBE(++x);
printfC'y是%d\n "。y);
}

在上面的例子中,y是多少?实际上,y既不等于125(5的立方),也不等于336(6* 7*8),而是等于512。因为变量x在作为参数传递给宏时是自动递增的,所以上面例子中的CUBE宏实际上是以下面的形式展开的:
y =((++ x)*(++ x)*(++ x));
这样,你每引用一次X,X就会自己增加一次,所以你得到的结果和你预想的相差甚远。在上面的例子中,由于X被引用了3次,并且使用了自动递增运算符,所以当你展开宏的代码时,X实际上是8,你会得到8的立方而不是5的立方。
上述错误相当普遍,笔者也亲身见过有多年C编程经验的人犯这样的错误。因为在程序中检查这种错误是非常费力的,所以要充分重视。试试上面的例子,自己看看那个令人惊讶的结果值(512)。
宏还可以使用一些特殊的运算符,例如字符串运算符“#”和。连接运算符“# #”。“#”运算符可以将宏参数转换为带双引号的字符串。请看下面的例子:
定义DEBUG_VALUE(v)printf(# v " is equal to % d . \ n ",v)
可以使用DEBUG _ VALUE宏来检查程序中变量的值。请看下面的例子:[/br
DEBUG _ VALUE(x);
上面的语句会在屏幕上打印出“x等于20”。这个例子说明了宏使用的“#”运算符是一个非常方便的调试工具。
运算符“# #”的作用是将两个独立的字符串连接成一个字符串。详见5.16。

位律师回复
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » C语言编程常见问题解答之编译预处理

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情