C语言——程序环境和预处理(下)

简介: C语言——程序环境和预处理(下)

3. 预处理详解


3.1 预定义符号

__FILE__      //进行编译的源文件
__LINE__     //文件当前的行号
__DATE__    //文件被编译的日期
__TIME__    //文件被编译的时间
__STDC__    //如果编译器遵循ANSI C,其值为1,否则未定义

这些预定义符号都是语言内置的。

举个栗子:

printf("file:%s line:%d\n", __FILE__, __LINE__);

3.2 #define

3.2.1 #define 定义标识符

语法:

#define name stuff

举个栗子:

#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;

这里会出现语法错误


3.2.2 #define 替换规则

       在程序中扩展#define定义符号和宏时,需要涉及几个步骤。


1. 在调用宏时,首先对参数进行检查,看看是否包含任何由#define定义的符号。如果是,它们首先 被替换。


2. 替换文本随后被插入到程序中原来文本的位置。对于宏,参数名被他们的值替换。


3. 最后,再次对结果文件进行扫描,看看它是否包含任何由#define定义的符号。如果是,就重复上 述处理过程。


注意:


1. 宏参数和#define 定义中可以出现其他#define定义的变量。但是对于宏,不能出现递归。


2. 当预处理器搜索#define定义的符号的时候,字符串常量的内容并不被搜索。


3.2.3宏和函数对比


宏通常被应用于执行简单的运算。比如在两个数中找出较大的一个。


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

那为什么不用函数来完成这个任务?


原因有二:


1. 用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比 函数在程序的规模和速度方面更胜一筹。

2. 更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的表达式上使用。反之 这个宏怎可以适用于整形、长整型、浮点型等可以用于>来比较的类型。宏是类型无关的。

当然和宏相比函数也有劣势的地方:


        1. 每次使用宏的时候,一份宏定义的代码将插入到程序中。除非宏比较短,否则可能大幅度增加程序 的长度。

       2. 宏是没法调试的。


        3. 宏由于类型无关,也就不够严谨。


        4. 宏可能会带来运算符优先级的问题,导致程容易出现错。

宏有时候可以做函数做不到的事情。比如:宏的参数可以出现类型,但是函数做不到

#define MALLOC(num, type)\
 (type *)malloc(num * sizeof(type))
...
//使用
MALLOC(10, int);//类型作为参数
//预处理器替换之后:
(int *)malloc(10 * sizeof(int));

宏和函数的一个对比

f822040e220b4fea8a1473c7cc526edd.png

命名约定 一般来讲函数的宏的使用语法很相似。


所以语言本身没法帮我们区分二者。


那我们平时的一个习惯是:


把宏名全部大写

函数名不要全部大写


4. 其他预处理指令


#error


#pragma


#line ...


不做介绍,自己去了解。


#pragma


pack()在结构体部分介绍  


相关文章
|
1月前
|
存储 自然语言处理 编译器
【C语言】编译与链接:深入理解程序构建过程
【C语言】编译与链接:深入理解程序构建过程
|
1月前
|
编译器 C语言
C语言--预处理详解(1)
【10月更文挑战第3天】
|
1月前
|
编译器 Linux C语言
C语言--预处理详解(3)
【10月更文挑战第3天】
|
20天前
|
C语言
【c语言】你绝对没见过的预处理技巧
本文介绍了C语言中预处理(预编译)的相关知识和指令,包括预定义符号、`#define`定义常量和宏、宏与函数的对比、`#`和`##`操作符、`#undef`撤销宏定义、条件编译以及头文件的包含方式。通过具体示例详细解释了各指令的使用方法和注意事项,帮助读者更好地理解和应用预处理技术。
22 2
|
1月前
|
C语言
C语言--预处理详解(2)
【10月更文挑战第3天】
|
1月前
|
存储 文件存储 C语言
深入C语言:文件操作实现局外影响程序
深入C语言:文件操作实现局外影响程序
|
1月前
|
编译器 C语言
C语言预处理详解
C语言预处理详解
|
1月前
|
Linux C语言 iOS开发
MacOS环境-手写操作系统-06-在mac下通过交叉编译:C语言结合汇编
MacOS环境-手写操作系统-06-在mac下通过交叉编译:C语言结合汇编
19 0
|
1月前
|
C语言 C++
C语言 之 内存函数
C语言 之 内存函数
34 3
|
9天前
|
C语言
c语言调用的函数的声明
被调用的函数的声明: 一个函数调用另一个函数需具备的条件: 首先被调用的函数必须是已经存在的函数,即头文件中存在或已经定义过; 如果使用库函数,一般应该在本文件开头用#include命令将调用有关库函数时在所需要用到的信息“包含”到本文件中。.h文件是头文件所用的后缀。 如果使用用户自己定义的函数,而且该函数与使用它的函数在同一个文件中,一般还应该在主调函数中对被调用的函数做声明。 如果被调用的函数定义出现在主调函数之前可以不必声明。 如果已在所有函数定义之前,在函数的外部已做了函数声明,则在各个主调函数中不必多所调用的函数在做声明
26 6