C 语言编程 — 宏定义与预处理器指令
目录
文章目录
前文列表
《程序编译流程与 GCC 编译器》
《C 语言编程 — 基本语法》
《C 语言编程 — 基本数据类型》
《C 语言编程 — 变量与常量》
《C 语言编程 — 运算符》
《C 语言编程 — 逻辑控制语句》
《C 语言编程 — 函数》
《C 语言编程 — 高级数据类型 — 指针》
《C 语言编程 — 高级数据类型 — 数组》
《C 语言编程 — 高级数据类型 — 字符串》
《C 语言编程 — 高级数据类型 — 枚举》
《C 语言编程 — 高级数据类型 — 结构体与位域》
《C 语言编程 — 高级数据类型 — 共用体》
《C 语言编程 — 高级数据类型 — void 类型》
《C 语言编程 — 数据类型的别名》
《C 语言编程 — 数据类型转换》
宏
宏是预处理器指令。它用来将一个标识符(宏名)定义为一个字符串,被定义的字符串称为替换文本。程序在预编译阶段,所有的宏名都会被定义的字符串替换,这便是宏替换。它的功能非常强大,甚至自成一门语言,有兴趣的可以参看宏编程。宏定义通常被用来简化代码的实现,让代码的逻辑更加清晰。
宏的工作原理是定义一些参数,将这些参数复制到特定的格式(宏定义)中,通过修改宏定义(以 #define 为开头的代码片段)或者参数,宏可以生成我们想要的代码。
预处理器
C 预处理器(C Preprocessor)简写为 CPP,又称预编译器,它并不是 C 编译器的组成部分,但是它是编译过程中一个单独的步骤。本质上,C 预处理器不过是一个文本替换工具而已,它们会指示编译器在实际的编译工作之前完成所需的预处理准备。
预处理器指令
C 语言中,所有的预处理器指令都是以 # 开头的。它必须是第一个非空字符,通常位于源文件首部。下面列出了所有重要的预处理器指令:

预处理器指令示例
- 这个指令告诉 CPP 把所有的 MAX_ARRAY_LENGTH 替换为 20。通常用于定义常量。
#define MAX_ARRAY_LENGTH 20
- 这些指令告诉 CPP 从系统库中获取头文件 stdio.h,并添加文本到当前的源文件中。
#include <stdio.h>
- 这些指令告诉 CPP 从本地目录中获取头文件 myheader.h,并添加内容到当前的源文件中。
#include "myheader.h"
- 这个指令告诉 CPP 取消已定义的 FILE_SIZE,并重新定义它为 42。
#undef FILE_SIZE
#define FILE_SIZE 42
- 这个指令告诉 CPP 只有当 MESSAGE 未定义时,才定义 MESSAGE。
#ifndef MESSAGE
#define MESSAGE "You wish!"
#endif
- 这个指令告诉 CPP 如果定义了 DEBUG,则执行处理语句。在编译时,如果向 gcc 编译器传递了 -DDEBUG 开关选型,这个指令就非常有用。它定义了 DEBUG,可以在编译期间随时开启或关闭。
#ifdef DEBUG
/* Your debugging statements here */
#endif
预定义宏
C 语言中定义了许多宏。在编程中可以直接使用这些预定义的宏,但是不能直接修改它们。

#include <stdio.h>
int main() {
printf("File :%s\n", __FILE__ );
printf("Date :%s\n", __DATE__ );
printf("Time :%s\n", __TIME__ );
printf("Line :%d\n", __LINE__ );
printf("ANSI :%d\n", __STDC__ );
return 0;
}
运行:
$ ./main
File :main.c
Date :Apr 4 2020
Time :14:13:10
Line :7
ANSI :1
预处理器指令运算符
C 预处理器提供了下列的运算符来帮助创建宏:
宏延续运算符
一个宏通常写在一个单行上。但是如果宏太长,一个单行容纳不下,则使用宏延续运算符 \。例如:
#define message_for(a, b) printf(#a " and " #b ": We love you!\n")
// or
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
字符串常量化运算符
在宏定义中,当需要把一个宏的参数转换为字符串常量时,则使用字符串常量化运算符 #。例如:
#include <stdio.h>
#define message_for(a, b) \
printf(#a " and " #b ": We love you!\n")
int main(void) {
message_for(Carole, Debra);
return 0;
}
运行:
$ ./main
Carole and Debra: We love you!
标记(Token)粘贴运算符
在宏定义中,标记粘贴运算符 ## 会合并两个参数。它允许将两个独立的标记被合并为一个标记。例如:
#include <stdio.h>
#define tokenpaster(n) printf ("token" #n " = %d", token##n)
int main(void) {
int token34 = 40;
tokenpaster(34);
return 0;
}
运行:
$ ./main
token34 = 40
上述示例会从编译器产生下列的实际输出:
printf ("token34 = %d", token34);
将 token##n 连接为 token34。在这里,使用了字符串常量化运算符 # 和标记粘贴运算符 ##。
defined() 运算符
defined() 运算符是用在常量表达式中的,用来判断一个标识符是否已经使用 #define 定义过。如果指定的标识符已定义,则值为真。
#include <stdio.h>
#if !defined (MESSAGE)
#define MESSAGE "You wish!"
#endif
int main(void) {
printf("Here is the message: %s\n", MESSAGE);
return 0;
}
参数化的宏
CPP 一个强大的功能是可以使用参数化的宏来模拟函数。
// 一般函数
int square(int x) {
return x * x;
}
// 使用参数化的宏来模拟函数
#define square(x) ((x) * (x))
e.g.
#include <stdio.h>
#define MAX(x,y) ((x) > (y) ? (x) : (y))
int main(void) {
printf("Max between 20 and 10 is %d\n", MAX(10, 20));
return 0;
}
C 语言编程 — 宏定义与预处理器指令的更多相关文章
- C++ 内置宏定义 与 预编译指令
内置宏和预编译指令, 在代码调试.单元测试.跨平台代码中经常会用到.这里记录一下. 1. 内置宏 (文件名,当前行号,当前日期,当前时间,当前执行方法名) __FILE____LINE____DATE ...
- [No0000FC]C# 预处理器指令
预处理器指令指导编译器在实际编译开始之前对信息进行预处理. 所有的预处理器指令都是以 # 开始.且在一行上,只有空白字符可以出现在预处理器指令之前.预处理器指令不是语句,所以它们不以分号(;)结束. ...
- 雷林鹏分享:C# 预处理器指令
C# 预处理器指令 预处理器指令指导编译器在实际编译开始之前对信息进行预处理. 所有的预处理器指令都是以 # 开始.且在一行上,只有空白字符可以出现在预处理器指令之前.预处理器指令不是语句,所以它们不 ...
- C语言笔记 10_文件读写&预处理器
文件读写 上一章我们讲解了 C 语言处理的标准输入和输出设备.本章我们将介绍 C 程序员如何创建.打开.关闭文本文件或二进制文件. 一个文件,无论它是文本文件还是二进制文件,都是代表了一系列的字节.C ...
- Docs-.NET-C#-指南-语言参考-预处理器指令:#region(C# 参考)
ylbtech-Docs-.NET-C#-指南-语言参考-预处理器指令:#region(C# 参考) 1.返回顶部 1. #region(C# 参考) 2015/07/20 利用 #region,可以 ...
- Docs-.NET-C#-指南-语言参考-预处理器指令:#line(C# 参考)
ylbtech-Docs-.NET-C#-指南-语言参考-预处理器指令:#line(C# 参考) 1.返回顶部 1. #line(C# 参考) 2015/07/20 借助 #line,可修改编译器的行 ...
- Docs-.NET-C#-指南-语言参考-预处理器指令:#error(C# 参考)
ylbtech-Docs-.NET-C#-指南-语言参考-预处理器指令:#error(C# 参考) 1.返回顶部 1. #error(C# 参考) 2015/07/20 #error 可从代码中的特定 ...
- Docs-.NET-C#-指南-语言参考-预处理器指令:#warning(C# 参考)
ylbtech-Docs-.NET-C#-指南-语言参考-预处理器指令:#warning(C# 参考) 1.返回顶部 1. #warning(C# 参考) 2015/07/20 #warning 允许 ...
- Docs-.NET-C#-指南-语言参考-预处理器指令:#undef(C# 参考)
ylbtech-Docs-.NET-C#-指南-语言参考-预处理器指令:#undef(C# 参考) 1.返回顶部 1. #undef(C# 参考) 2018/06/30 #undef 允许你定义一个符 ...
- Docs-.NET-C#-指南-语言参考-预处理器指令:#define(C# 参考)
ylbtech-Docs-.NET-C#-指南-语言参考-预处理器指令:#define(C# 参考) 1.返回顶部 1. #define(C# 参考) 2018/06/30 使用 #define 来定 ...
随机推荐
- OpenAtom OpenHarmony分论坛,今天14:00见!附大事记精彩发布
2022开放原子全球开源峰会 OpenAtom OpenHarmony分论坛 万物互联,使能千行百业 整装待发!精彩今日揭晓与您相约7月27日 14:00
- C++ 字符串完全指南:学习基础知识到掌握高级应用技巧
C++ 字符串 字符串用于存储文本. 一个字符串变量包含由双引号括起来的一组字符: 示例 创建一个 string 类型的变量并为其赋值: string greeting = "Hello&q ...
- APM vs NPM
概述 APM:Application Performance Monitoring 的简称,即应用性能监控. NPM:Network Performance Monitoring 的简称,即网络性能监 ...
- HarmonyOS分布式文件系统开发指导
分布式文件系统概述 分布式文件系统(hmdfs,HarmonyOS Distributed File System)提供跨设备的文件访问能力,适用于如下场景: ● 两台设备组网,用户可以利用一台设 ...
- 报表如何集成 echarts 官网示例图
Echarts,江湖人称一个纯 Javascript 的图表库,图形种类星罗棋布且个个颜值爆表,可以轻松驾驭 PC 和移动设备,与绝大部分浏览器都可称兄道弟,而且已然众多拥趸,还有不少报表对它采取了嫁 ...
- python实现:有一个列表为num_list,找到一个具有最大和的连续子列表,返回其最大和。
# 有一个列表为num_list,找到一个具有最大和的连续子列表,返回其最大和.# 示例:# 输入: [-3,1,-1,6,-1,2,4,-5,4]# 输出: 11# 解释: 连续子数组 [6,-1, ...
- pypinyin 获取拼音,作为智能设备的唤醒比对结果
from pypinyin import lazy_pinyin,TONE,TONE2,TONE3,NORMAL a = "小七同学" b = "小琦同学" c ...
- 阿里云EMAS移动测试,帮您快速掌握移动端兼容性测试技巧
简介: 兼容性测试用于验证应用在不同设备上进行安装/启动/登录/不同版本覆盖安装/卸载等操作时,是否存在兼容性问题:如界面适配问题.应用性能等,现阿里云EMAS套餐免费试用,帮您快速掌握移动端兼容性测 ...
- 好云推荐官丨飞天加速之星怎样选择云服务器ECS?
编者按:本文来自"好云推荐官"活动的技术博主投稿,作者(昵称天狼)曾入选首届"飞天加速之星",获得飞天人气奖. 你是否还在苦苦地寻找一家合适的云厂商,寻找合 ...
- IT人的年夜饭,也太香了吧
简介: 平时的IT人,奋战在修复bug前线,起早与贪黑齐飞,调休共假期待定.到了新春佳节,对于IT人来说,没有什么是比一顿年夜饭更让人熨贴肺腑的了.为了让废寝忘食编程序.闻机起早保运维的IT人过一个 ...