我嘞个豆!原来 C/C++ 宏还可以这么玩啊?
在 C/C++ 中,宏定义是一种用于在编译时替换文本的机制。在某些情况下,你可能会想要动态地改变宏的值,而这可以通过使用宏参数来实现。当然,这些只是宏定义的基本操作。下面我们来看看关于宏的进阶操作。
一、字符串化操作(#)
在 C/C++ 中,字符串化操作(#)可以将一个宏参数转换为字符串字面量(并非简单的添加双引号,详情可见下面的例子)。
1 |
|
程序输出结果为:
1 |
|
二、拼接操作(##)
在 C/C++ 中,拼接操作(##)可以将两个宏参数连接在一起。因为宏替换是在编译阶段运行的,所以利用该操作可以实现很多“奇怪”的代码🤓。详情请参考下面的程序示例,因为比较简单就不做详细解释了。
1 |
|
程序输出结果为:
1 |
|
三、预定义宏/预处理器宏
在 C/C++ 中,预定义宏是一种特殊类型的宏,它们在编译时已经定义,并且无法被用户定义。它们是编译器内置的,用于提供有关编译器的信息。
3.1 标准预定义标识符
根据 ISO C99 和 ISO C++11 规范,C/C++ 语言中预定义了以下标识符:
__func__
:封闭函数(用作 char 的函数局部 static const 数组)的未限定、未修饰名称。程序输出结果为:1
2
3
4
5
6
7
8
9
10
11
12#include <iostream>
using namespace std;
static void SeaEpoch(const string& url) {
cout << "当前执行函数:" << __func__ << endl;
}
int main() {
SeaEpoch("www.seayj.cn");
return 0;
}1
当前执行函数:SeaEpoch
3.2 标准预定义宏
根据 ISO C99、C11、C17 和 ISO C++17 标准,编译器提供了以下预定义宏:
__cplusplus
:当翻译单元编译为 C++ 时,定义为整数文本值,表示 C++ 标准的版本号。其他情况下则不定义。__DATE__
:当前源文件的编译日期。日期是Mmm dd yyyy
格式的恒定长度字符串文本。月份名Mmm
与 C 运行时库 (CRT)asctime
函数生成的缩写月份名相同。如果值小于 10,则日期dd
的第一个字符为空格。任何情况下都会定义此宏。__FILE__
:当前源文件的名称。__FILE__
展开为字符型字符串文本。要确保显示文件的完整路径,请使用(诊断中源代码文件的完整路径)/FC
。任何情况下都会定义此宏。__LINE__
:定义为当前源文件中的整数行号。可使用#line
指令来更改此宏的值(例如#line 1
可将当前行号设置为 1,后续行号根据该行行号进行累加)。__LINE__
值的整型类型因上下文而异。任何情况下都会定义此宏。__STDC__
:仅在编译为 C,并且指定了/Za
编译器选项时,定义为 1。从 Visual Studio 2022 17.2 版本开始,当编译为 C 并指定/std:c11
或/std:c17
编译器选项时,它定义为 1。其他情况下则不定义。__STDC_HOSTED__
:如果实现是托管实现并且支持整个必需的标准库,则定义为 1。其他情况下则定义为 0。__STDC_NO_ATOMICS__
如果实现不支持可选的标准原子,则定义为 1。当编译为 C 且指定 /std C11 或 C17 选项之一时,MSVC 实现会将其定义为 1。__STDC_NO_COMPLEX__
如果实现不支持可选的标准复数,则定义为 1。当编译为 C 且指定 /std C11 或 C17 选项之一时,MSVC 实现会将其定义为 1。__STDC_NO_THREADS__
如果实现不支持可选的标准线程,则定义为 1。当编译为 C 且指定 /std C11 或 C17 选项之一时,MSVC 实现会将其定义为 1。__STDC_NO_VLA__
如果实现不支持可选的可变长度数组,则定义为 1。当编译为 C 且指定 /std C11 或 C17 选项之一时,MSVC 实现会将其定义为 1。__STDC_VERSION__
当编译为 C 且指定 /std C11 或 C17 选项之一时定义。对于/std:c11
,它扩展到 201112L;对于/std:c17
,则扩展到 201710L。__STDCPP_DEFAULT_NEW_ALIGNMENT__
当指定/std:c17
或更高版本时,此宏会扩展为size_t
字面量,该字面量的对齐值由对非对齐感知的operator new
的调用所保证。较大的对齐值传递到对齐感知重载,例如operator new(std::size_t, std::align_val_t)
。有关详细信息,请参阅/Zc:alignedNew
(C++17 过度对齐的分配)。__STDCPP_THREADS__
:当且仅当程序可以有多个执行线程并编译为 C++ 时,定义为 1。其他情况下则不定义。__TIME__
:预处理翻译单元的翻译时间,时间是hh:mm:ss
格式的字符型字符串文本,与 (CRT)asctime
函数返回的时间相同,任何情况下都会定义此宏。
下面可以看一下这个示例,可能是标准预定义宏的一种使用场景:
1 |
|
程序输出结果为:
1 |
|
3.3 MSVC 特有的预定义宏
对于 MSVC 编译器,微软还设置了很多其他有用的预定义宏。这里不做更多详细的介绍了,详情可见 Microsoft 专用预定义宏
参考资料
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 SeaEpoch!
评论