首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C语言预处理完全指南:从预定义符号到头文件包含

C语言预处理完全指南:从预定义符号到头文件包含

作者头像
码途随笔
发布2026-01-12 20:04:24
发布2026-01-12 20:04:24
960
举报

一、预定义符号

__FILE__:文件名 __TIME__:编译一瞬间的时间 __LINE__:符号所在的行号 __DATE__:文件被编译的日期

代码语言:javascript
复制
#include<stdio.h>
int main()
{
	printf("%s\n", __FILE__);
	printf("%d\n", __LINE__);
	printf("%s\n", __DATE__);
	printf("%s\n", __TIME__);
	return 0;
}

__STDC__判断编译器是否遵循ANSIC,如果遵循,其值为1

二、#define

在预处理命令阶段完成

2.1 #define定义常量

#define可以定义常量,也可以定义字符串

代码语言:javascript
复制
#define MAX 10
#define STR "haha"

后面也可以加语句(代码)

代码语言:javascript
复制
#define  forever for(;;)
int main()
{
	forever;
	return 0;
}

补充:续行符

在这里插入图片描述
在这里插入图片描述

续行符后面什么都不能有(比如空格) 注意: 不能define后面不能加分号(因为符号替换后也会加分号)

2.2 #define定义宏

宏与函数类似(没有参数部分,并且直接完成替换)

代码语言:javascript
复制
#define Fuc(x) x*x
int main()
{
	int ret = Fuc(3);
	printf("%d", ret);
	return 0;
}

宏定义是直接替换进去的,不会帮你计算,需考虑宏文本里面的优先级和传参的优先级,(当参数传a+1时),解决方法:加括号

在这里插入图片描述
在这里插入图片描述

有时候整体也要加括号 #define DOUBLE(x) ((x)+(x))

在这里插入图片描述
在这里插入图片描述

总结:所以用于对数值表达式进行求值的宏定义都应该用这种方式加上括号,避免在使用宏时由于参数中的操作符或邻 近操作符之间不可预料的相互作用。

2.3 副作用

比如:b=a++实现了b=a+1的效果,但产生了a=a+1的副作用

当宏参数在宏的定义中出现超过一次的时候,如果参数带有副作用,那么你在使用这个宏的时候就可能出现危险导致不可预测的后果。副作用就是表达式求值的时候出现的永久性效果

代码语言:javascript
复制
#define MAX(x,y) ((x>y)?(x):(y))
int main()
{
	int a = 3;
	int b = 5;
	int ret = MAX(a++, b++);
	printf("%d\n", ret);
	printf("%d\n", a);
	printf("%d\n", b);
	return 0;
}
在这里插入图片描述
在这里插入图片描述

2.4 宏替换的规则

在这里插入图片描述
在这里插入图片描述

2.5 宏和函数对比

  • 宏通常进行简单的运算 比如求俩个数的较大值 #define MAX(x,y) ((x>y)?(x):(y)) 原因:因为调用函数需要调用函数、执行运算、返回参数需要时间

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

在这里插入图片描述
在这里插入图片描述

有一些宏可以做到,但函数不能做到的事(可以传类型)

代码语言:javascript
复制
#define Malloc(x,type) (type*)malloc(x*sizeof(type))
int main()
{
	int* ptr = Malloc(3, int);
	return 0;
}

三、#和##

3.1 #运算符

补充:两者效果一样

代码语言:javascript
复制
	printf("haha""hehe\n");
	printf("hahahehe\n");

让参数直接转为字符串变量#a

代码语言:javascript
复制
#define Print(n,format) printf(#n " value is "format"\n",n)
int main()
{
	int a = 3;
	double b = 4.0;
	float c = 7.3f;
	Print(a, "%d");
	Print(b, "%lf");
	Print(c, "%f");
	return 0;
}

3.2 ##运算符

功能:把两端的符号看成一个符号

代码语言:javascript
复制
#define GEN(type) \
type type##_max(type x,type y)\
{\
return x>y?x:y;\
}
GEN(int);
GEN(double);
int main()
{
	int ret =int_max(3, 4);
	double ret1 =double_max(9.0, 3.0);
	printf("%d\n", ret);
	printf("%lf\n", ret1);
}

四、命名习惯

  • 宏一般大写(也有特例:offsetof:计算结构体成员相交与起始位置的偏移量)
  • 函数名一般不用全大写

五、undef与命令行定义

  • #undef 功能:移除宏定义
代码语言:javascript
复制
#define MAX 10
int main() 
{
	int a = MAX;
#undef MAX
	int b = MAX;
	return 0;
}
  • 命令行定义(在gcc环境适合使用)
在这里插入图片描述
在这里插入图片描述

六、条件编译

条件为真,代码段就编译,条件为假,代码段就不编译 常见的条件编译指令:

  • 单分支
代码语言:javascript
复制
#if 常量表达式//(表达式可以为零,该表达式的真假判断代码段执行不执行)
……
#endif
  • 多分支
代码语言:javascript
复制
#define M 7
int main()
{
#if M==0
	printf("haha");
#elif M==1
	printf("hehe");
#elif M==3
	printf("666");
#else
	printf("999");
#endif
}
  • 判断定没定义

第一种写法

代码语言:javascript
复制
#define M
int main()
{
#if defined(M)
	printf("haha");
#endif
	return 0;
}

第二种写法

代码语言:javascript
复制
#define M 2
int main()
{
#ifdef M
	printf("haha");
#endif
	return 0;
}

第三种写法:没定义执行(反过来)

代码语言:javascript
复制
//#define M 2
int main()
{
#if !defined(M)
	printf("haha");
#endif
	return 0;
}

第四种写法

代码语言:javascript
复制
//#define M 2
int main()
{
#ifndef M
	printf("haha");
#endif
	return 0;
}

七、头文件的包含

两种方式的区别 用“add.h”先在源文件所在目录下查找,如果该头文件未找到,编译器就像查找库函数头文件一样在标准位置查找头文件。如果找不到就提示编译错误。

代码语言:javascript
复制
#include"add.h"
#include<stdio.h>

防止多次包含头文件 有以下方法 方法一:

代码语言:javascript
复制
#ifdef ADD_H
#define ADD_H
int add(int x, int y);
#endif

方法二:

代码语言:javascript
复制
#pragma once
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2026-01-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、预定义符号
  • 二、#define
    • 2.1 #define定义常量
    • 2.2 #define定义宏
    • 2.3 副作用
    • 2.4 宏替换的规则
    • 2.5 宏和函数对比
  • 三、#和##
    • 3.1 #运算符
    • 3.2 ##运算符
  • 四、命名习惯
  • 五、undef与命令行定义
  • 六、条件编译
  • 七、头文件的包含
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档