随笔 - 163, 文章 - 1, 评论 - 20, 阅读 - 14万
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

C 语言编译预处理

Posted on   steve.z  阅读(89)  评论(0编辑  收藏  举报

一、编译预处理概念

1、编译预处理不是 C 语言本身的内容,是 C 编译系统提供的功能。在通常的编译之前,编译系统要预先对这些命令进行处理,之后才对 C 程序进行编译,生成目标代码。

特别注意:所有预处理命令均以 # 开头,末尾不加分号。

2、以下是三种预处理命令:

宏定义

#define PI 3.1415926

文件包含

#include <stdio.h>
#include "c_file1.c"

条件编译

#ifdef 标识符
	// TODO1
#else
	// TODO2
#endif

二、宏定义 & 文件包含 & 条件编译

1、宏定义

宏定义可以分为两种:1、不带参数的宏定义;2、带参数的宏定义。二者都是简单的字符串替换。

① 不带参数的宏定义

// 不带参数的宏定义方式
#define 标识符 一串字符

// 例如(以下宏定义中 PI 即为“宏名”):
#define PI 3.1415926

// 宏定义的作用:用 “标识符” 后的 “一串字符” 来替换程序中的 “标识符”
// 例如:#define PI 3.1415926
// 表示用 3.1415926 替换程序中的所有标识符 PI

// 参考代码
#include <stdio.h>
#define PI 3.1415926

int main(int argc, const char * argv[]) {
    // r 表示半径;l 表示周长; s 表示面积
    double r = 6, l = 0, s = 0;
    l = 2 * PI * r; // 计算周长
    s = PI * r * r; // 计算面积
    
    printf("周长 = %.2f;  面积 = %.2f\n", l, s);
    
    // ★★★特别提醒:双引号中的 PI 不会被替换为 3.1415926
  	// 双引号引起来的字符串常量中出现了与宏名相同的内容,不能将其理解为宏名,更不能将其展开。
    printf("PI = %.7f\n", PI);
    
    return 0;
}


/*
以上代码运行结果如下:
周长 = 37.70;  面积 = 113.10
PI = 3.1415926
*/

*** 在预处理时,先做如下替换,然后才开始编译:***

l = 2 * PI * r; 会被替换成 l = 2 * 3.1415926 * r;
s = PI * r * r; 会被替换成 s = 3.1415926 * r * r;

*** 特别提醒:***

1> 宏名前后应有空格

2> 宏定义是用宏名代替一个字符序列,只是一种简单的替换,不进行正确性检查。

例如:

#define PI = 3.14abc15926
s = PI * r * r;
// 以上代码在预编译时只做替换操作,不会出错。在编译时才会报错。因为 3.14abc15926 不是合法的数字。

*** 易错提醒:***

宏定义时,为了保证计算正确性,需要适时加小括号。

#define PI 2 + 1.1415926
s = PI * r * r;

// s = PI * r * r; 展开后形式是:s = 2 + 1.1415926 * r * r; 由于运算符优先级问题此时计算的结果 s 是错误的。

// 应该将宏定义改为:
#define PI (2 + 1.1415926) 
// 此时,s = PI * r * r; 展开后形式是:s = (2 + 1.1415926) * r * r; 计算结果正确

*** 嵌套宏定义 😗**

#include <stdio.h>
#define PI 3.1415926
#define RADIUS 3.0
#define AREA PI * RADIUS * RADIUS

int main(int argc, const char * argv[]) {
    printf("area = %f\n", AREA); // 输出结果为:area = 28.274333
    return 0;
}

/*
以上宏展开的过程:
1. 首先对 #define AREA PI * RADIUS * RADIUS 中的 AREA 展开得到:#define AREA 3.1415926 * 3.0 * 3.0

2. 再对 printf("area = %f\n", AREA); 中的 AREA 展开得到:
printf("area = %f\n", 3.1415926 * 3.0 * 3.0);
*/

*** 宏名的作用范围:***

宏名的作用域是从定义点开始到本源文件结束,或用 #undef 取消定义之前。例如:

#define PI 3.1415926
#define G 9.8
int main(int argc, const char * argv[]) {
  // 在 main() 函数中 PI 和 G 均可以正常使用
}

// 以下这行代码取消了宏 G 的定义
#undef G

void func() {
  // 在该函数中只能使用宏 PI,而不能使用宏 G 了
}

// 宏 G 的作用域是从定义点开始到 #undef G 之前。
// 宏 PI 的作用域是从定义点开始到本源文件结束。

② 带参数的宏定义

相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示