C语言预处理上

简介: C语言预处理上

1.预定义符号


下面的预定义符号都是语言内置的,我们可以直接使用


__FILE__//进行编译的源文件

__LINE__//当前行号

__DATE__//文件被编译的日期

__TIME__//文件被编译的时间


举个例子,打印当前文件被编译的日期和时间:


int main()
{
  printf("%s %s",__DATE__,__TIME__);
  return 0;
}


2.#define


#define定义标识符

语法:


#define name stuff

1

如:


#define MAX 1000
#define Peo Peoinfo

1

2

在程序中,可以直接使用这些标识符,举个例子:


#define MAX 1000
#define Peo Peoinfo
int main()
{
  int Peo = MAX;
}


要注意一点:


在define定义时,不要在最后加上;


#define MAX 1000;//在后续运行中会出现错误
#define MAX 1000//正确写法

1

2

在定义标识符时,如果像一下定义,会出现问题


#define A 1+3
#define B 4+3
int main()
{
  int c = A*B;
}


这里如果我们主观上会认为A就是1+3的值为4,B是4+3的值为7,所以在后面的替换后,int c = A*B替换成int c = 4*7,c的值就是28,其实这是错误的


在预处理中的替换是“直接替换”,预处理后int c = A*B会变为int c = 1+3*4+3,由于运算符有优先顺序,c的为16.


#define定义宏
#define 机制包括了一个规定,允许把参数替换到文本中,这种实现通常称为宏(macro)或定义宏(define macro)。

宏的申明方式如下:


#define name( parament-list ) stuff
1

parameter-list为参数列表,参数会出现在stuff中

注意:

参数列表的左括号必须与name紧邻,中间不能有空格

如果之间有空格存在,参数列表就会被解释为stuff中的一部分


接下来举一个例子

定义一个宏,这个宏接收一个参数x


#define SQUARE(x) x*x

1

将宏声明之后,在预处理中,例如SQUARE(5)就会被5*5所替换

#define SQUARE(x) x*x
int main()
{
  int num = SQUARE(5);
  printf("%d",num);//结果会输出5
}
1

面代码:


#define SQUARE(x) x*x
int main()
{
  int num = SQUARE(1+5);
  printf("%d",num);
}

,可能会认为这段代码打印结果是36,但事实上这个程序打印11


因为在替换文本时,参数x被替换成了1+5,所以语句变成了int num = 1+5*1+5


所以可以看出,由替换产生的表达式并没有按照预想的次序进行求值


其实在宏定义时,加上两个括号就可以解决这个问题


#define SQUARE(x) (x)*(x)

1

在预处理之后替换成:int num = (1+5)*(1+5)


继续观看一下代码:


#define SUM(x) (x)+(x)
int main()
{
  printf("%d",10*SUM(5));
}


这个代码仍有问题

在预处理后会替换成:


printf("%d",10*(5)+(5));
1

可以看出,由于表达式的优先次序,这个宏不会按照我们的想法进行正确计算


所以宏定义表达式两边加上一对括号就可以了


#define SUM(x) ((x)+(x))
1

用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中

的操作符或邻近操作符之间不可预料的相互作用。


#define 替换规则

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

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

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

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

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

#和##

#的作用是


把宏的参数插入到字符串中


首先我们先看一个代码:


printf("hello ""world");
1

我们将"hello world"分写成2个字符串,运行代码后,仍然输出hello world

所以可以看出字符串是有自动连接的特点的


再看一个代码:


int main()
{
  printf("the size of int is %d\n", sizeof(int));
  printf("the size of char is %d\n", sizeof(char));
  printf("the size of short is %d\n", sizeof(short));
  printf("the size of float is %d\n", sizeof(float));
  printf("the size of double is %d\n", sizeof(double));
  return 0;
}


如果我们想要计算每个类型的大小,并且要同字符串一块打印出来,每打印一次都需要写一段字符串,而且字符串中的要写的类型还不同,十分麻烦

所以我们可以使用宏


所以可以在定义宏时,通过使用#,把参数插入字符串中


#define PRINT(type,size) printf("the size of " #type" is %d\n",size)
1

所以在使用宏时,就十分方便


int main()
{
  PRINT(int, sizeof(int));
  PRINT(char, sizeof(char));
  PRINT(short, sizeof(short));
  //……………………………………………………
  return 0;
}


##的作用是:


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

它允许宏定义从分离的文本片段创建标识符。


观察一下代码:


#define COMBINE(x,y) x##y
int main()
{
  int abcd = 10;
  printf("%d\n", COMBINE(ab, cd));//结果输出10
  return 0;
}


通过使用宏,##将x和y合成一个符号,在预处理后语句变为:printf("%d\n",abcd);


注意:这样的连接必须产生一个合法的标识符。否则其结果就是未定义的。



目录
相关文章
|
2月前
|
编译器 C语言
C语言--预处理详解(1)
【10月更文挑战第3天】
|
2月前
|
编译器 Linux C语言
C语言--预处理详解(3)
【10月更文挑战第3天】
|
2月前
|
自然语言处理 编译器 Linux
【C语言篇】编译和链接以及预处理介绍(上篇)1
【C语言篇】编译和链接以及预处理介绍(上篇)
42 1
|
1月前
|
C语言
【c语言】你绝对没见过的预处理技巧
本文介绍了C语言中预处理(预编译)的相关知识和指令,包括预定义符号、`#define`定义常量和宏、宏与函数的对比、`#`和`##`操作符、`#undef`撤销宏定义、条件编译以及头文件的包含方式。通过具体示例详细解释了各指令的使用方法和注意事项,帮助读者更好地理解和应用预处理技术。
24 2
|
2月前
|
编译器 Linux C语言
【C语言篇】编译和链接以及预处理介绍(下篇)
【C语言篇】编译和链接以及预处理介绍(下篇)
33 1
【C语言篇】编译和链接以及预处理介绍(下篇)
|
2月前
|
C语言
C语言--预处理详解(2)
【10月更文挑战第3天】
|
2月前
|
编译器 C语言
C语言预处理详解
C语言预处理详解
|
2月前
|
存储 C语言
【C语言篇】编译和链接以及预处理介绍(上篇)2
【C语言篇】编译和链接以及预处理介绍(上篇)
38 0
|
4月前
|
存储 自然语言处理 程序员
【C语言】文件的编译链接和预处理
【C语言】文件的编译链接和预处理
|
4月前
|
程序员 编译器 C语言
C语言中的预处理指令及其实际应用
C语言中的预处理指令及其实际应用
90 0