C和指针(第14章---预处理器)

程序编写,编译第一步就是宏的声明,也称预处理器阶段,在编译之前,有删除注释,插入被#include指令包含的文件的内容、和#define所替换的符号等。

14.1 五种预处理符号

__FILE__     ''name.c''               进行编译的源文件名     

__LINE__         25                     文件当前的行号

__DATE__    ''Jan 14 2019''      文件被编译的日期

__TIME__     ''11:32:07''            文件被编译的时间

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

 

FILE、LINE使用场景主要是在调试程序时

DATE、TIME使用场景:在编译后的程序中加入一个时间标志,区别程序的不同版本
STDC使用场景:当要求程序严格遵循ANSI C标准时,标识符__STDC__就会被赋值为1

14.2 宏

注意:在使用宏定义计算表达式如:

#define SQUARE(x)   x*x
```
```
SQUARE(5)    //  5*5

而在下面情况下会产生意外:

Error:
    #define SQUARE(x)  x*x
    a = 5;
    printf("%d\n",SQUARE(a+1));   //  x*x预期结果为36
                                  //而实际上 a+1*a+1 = 5+1*5+1 =11

Right:
    #define SQUARE(x)  (x) * (x)
    a = 5;
    printf("%d\n",SQUARE(a+1));   //  (x)*(x)结果为(5+1)*(5+1) = 36 正确
    

所以在用宏定义一些计算表达式时需要注意符号之间的选择,否则会产生不可预期的错误。

14.2.1 #与##

’#‘的作用是将一个宏参数转换为一个字符串

#define PRINT(FORMAT,VALUE)    \
        printf( The value of  "#VALUE" \
        is "FORMAT"\n",VALUE)
 '''
 '''
PRINT("%d\n",x+3);

//将会输出 The value of x+3 is 25 
// 将x+3以字符串的形式打印出

’##‘的作用是把位于它两边的符号连接成一个新的符号(这个新符号必须是有定义的,否则非法)

#define ADD_TO_SUM(sum_number, value)  \
       sum ## sum_number += value
'''
'''
'''
ADD_TO_SUM(5, 25);

//将sum_number = 5 连接到sum后, 再将 value = 25 赋值给 sum5

14.2.3宏与函数

(1)宏还可以用作简单的计算,如比较两个表达式中的较大值

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

其中用宏完成这个计算功能比函数完成产生的代码更少,所以在小型计算工作中,宏的计算速度和程序规模都比函数要好;

更重要的是,函数必须声明一种特定的数据类型,而宏却突破了这种限制,可以用整形,长整形,浮点数等,换句话说,宏是与类型无关的。而需要注意的是,每次使用宏时,一份宏定义代码的拷贝都将插入到程序中,除非程序很短,否则使用宏可能大幅度增加程序的长度。

(2)宏可以完成函数无法完成的任务

#define MALLOC(n, type) \
        ( (type *)malloc( (n) * sizeof( type ) ) )

//可以定义类型为参数的宏定义,而函数却无法完成

但不合理的使用宏参数将会产生副作用,比如:

x+1执行几百万次每次得到的结果都相同 而x++执行超过一次之后,每执行一次x的值将发生变化,到最后每个代码段中出现一次x之变化一次,直至最后x的值无法确定。

 

 

14.3 条件编译

这部分简单了解 首先给出语法形式:

#if constant-expression(常量表达式)

          statements

#endif

14.4 文件包含

编译器支持两种不同类型的#include文件包含:

1. #include<filename>(处理调用函数库中的文件)

2.#include "filename" (处理本地头文件)

嵌套文件包含:在很多的大型程序中,往往包含了很多的头文件,而为了不重复调用同一头文件,可以用下面语法形式定义减少重复定义:

#ifndef __HEADERNAME_H

#define __HEADERNAME_H  1

#endif

 

 

14.7 警告的总结

1.不要在一个宏定义的末尾加上分号,使其成为一条完整的语句。

2.在宏定义中使用参数,但忘了在它们周围加上括号。

3.忘了在整个宏定义的两边加上括号。

 

14.8编程提示的总结

1.避免用#define指令定义可以用函数实现很长序列的代码。

2.在那些对表达式求值的宏中,每个宏参数出现的地方都应该加上括号,并且在整个宏定义的两边也加上括号。

3.采用命名约定,使程序员很容易看出某个标识符是否为#define宏。

5.只要适合就应该使用文件包含,不必担心它的额外开销。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值