C++ 宏
标识符 _ 与 __ 的含义
以单下划线(_)表明是标准库的变量
双下划线(__) 开头表明是编译器的变量
所以建议自己在命名的时候就不要用下划线开头,避免与标准库中的命名冲突了
C++内置宏定义
1. 标准内置宏定义
标准内置宏定义是由相关的语言标准定义的,因此对于实现了这些语言标准的编译器来说都是可使用的。
__FILE__:字符串格式,指示当前处理的文件路径。__LINE__:数字格式,指示当前处理的代码行号。#line:用来修改当前行的下一行的行号,即下一行的__LINE__由#line所指定的数字开始。
#include<stdio.h>
int main()
{
printf("Line: %d\n", __LINE__); // 5
#line 100
printf("Line: %d\n", __LINE__); // 100
return 0;
}
【注】__FILE__ 和 __LINE__ 宏主要用于错误处理,可以很方便地定位错误位置。
- C99 引入了
__func__,它和 GCC 提供的__FUNCTION__功能类似,二者都是字符串格式,指示当前处理的函数名。
【注】__func__ 和 __FUNCTION__ 本质上都不是宏,因为预处理器并不知道当前处理的函数名。
__DATE__:字符串格式,指示预处理器处理当前代码时的日期。__TIME__:字符串格式,指示预处理器处理当前代码时的时间。__STDC__:常数格式,一般值为1,用来告诉编译器遵守 ISO 标准 C 格式。__STDC_VERSION__:常数格式,指示当前使用的 C 语言标准版本,格式为yyyymmL,其中yyyy和mm分别表示年份和月份。__STDC_HOSTED__:数字格式,1表示要编译的对象是一个 Hosted Environment,否则表示不是。
【注】一个 Hosted Environment 表示具有可用的标准 C 库的完整功能。
__cplusplus:当使用了 C++ 编译器时,该宏被定义。因此可以它来测试编译时使用的编译器是 C 编译器还是 C++ 编译器。当__cplusplus被定义时,其格式和__STDC_VERSION__类似,只不过指示的是 C++ 语言的标准版本号。__OBJC__:当使用了 Objective-C 编译器时,该宏被定义。因此可以它来测试编译时使用的编译器是 C 编译器还是 Objective-C 编译器。当__OBJC__被定义时,其格式和__STDC_VERSION__类似,只不过指示的是 Objective-C 语言的标准版本号。__ASSEMBLER__:当预处理汇编语言时,该宏被定义。
2. 公共内置宏定义
公共内置宏定义是 GNU C 的扩展,只要使用了 GNU C 或者 GNU Fortran,这些宏都是可使用的。公共内置宏定义数量繁多,因此仅介绍常用的一些宏,更多可以参见官方文档:Common Predefined Macros
__COUNTER__:累加器,每次使用一次就递增1。因此可以用来当作唯一标识符使用。__GNUC__、__GNUC_MINOR__、__GNUC_PATCHLEVEL__:这些宏在使用了 C 预处理器的所有编译器中都定义了。它们分别指示了编译器的主版本号、次版本号和补丁版本号,均为整数常数。__BASE_FILE__:字符串格式,指示了主文件的路径。__FILE_NAME__:字符串格式,指示了当前文件路径的 Basename,即文件名。__INCLUDE_LEVEL__:数字格式,指示了当前嵌套深度。从0开始,每进入一次#include指示的头文件,__INCLUDE_LEVEL__增加1。__VERSION__:字符串格式,指示了编译器的版本号。__OPTIMIZE__、__OPTIMIZE_SIZE__、__NO_INLINE__:这些宏描述了编译模式。__OPTIMIZE__在所有的优化编译中都定义了,比如O1、O2等优化模式下;当编译器优化文件大小而不是运行速度时,__OPTIMIZE_SIZE__被定义;当编译器内联展开被禁止时,__NO_INLINE__被定义。__CHAR_UNSIGNED__、__WCHAR_UNSIGNED__:GCC 定义了宏__CHAR_UNSIGNED__、__WCHAR_UNSIGNED__当且仅当数据类型char或wchat_t在目标主机上是无符号类型。__CHAR_BIT__:数字格式,表示一个char数据类型占用多少 bit。__BYTE_ORDER__、__ORDER_LITTLE_ENDIAN__、__ORDER_BIG_ENDIAN__、__ORDER_PDP_ENDIAN__:__BYTE_ORDER__取值只能是__ORDER_LITTLE_ENDIAN__、__ORDER_BIG_ENDIAN__、__ORDER_PDP_ENDIAN__中的一种。表示多字节/字数据的存储模式,__ORDER_LITTLE_ENDIAN__、__ORDER_BIG_ENDIAN__即大小端模式,而__ORDER_PDP_ENDIAN__表示对于 16 位的字按照小端模式存储,对于 32 位双字中的 16 位子字是按照大端模式存储的。__FLOAT_WORD_ORDER__:表示浮点双字的存储模式,其值只能取__ORDER_LITTLE_ENDIAN__和__ORDER_BIG_ENDIAN__中的一种。
GCC 定义了一批和数据类型对应的宏,如下表所示:
| 数据类型 | 数据类型宏 |
|---|---|
| size_t | SIZE_TYPE |
| ptrdiff_t | PTRDIFF_TYPE |
| wchar_t | WCHAR_TYPE |
| wint_t | WINT_TYPE |
| intmax_t | INTMAX_TYPE |
| uintmax_t | UINTMAX_TYPE |
| sig_atomic_t | SIG_ATOMIC_TYPE |
| int8_t | INT8_TYPE |
| int16_t | INT16_TYPE |
| int32_t | INT32_TYPE |
| int64_t | INT64_TYPE |
| uint8_t | UINT8_TYPE |
| uint16_t | UINT16_TYPE |
| uint32_t | UINT32_TYPE |
| uint64_t | UINT64_TYPE |
| int_least8_t | INT_LEAST8_TYPE |
| int_least16_t | INT_LEAST16_TYPE |
| int_least32_t | INT_LEAST32_TYPE |
| int_least64_t | INT_LEAST64_TYPE |
| uint_least8_t | UINT_LEAST8_TYPE |
| uint_least16_t | UINT_LEAST16_TYPE |
| uint_least32_t | UINT_LEAST32_TYPE |
| uint_least64_t | UINT_LEAST64_TYPE |
| int_fast8_t | INT_FAST8_TYPE |
| int_fast16_t | INT_FAST16_TYPE |
| int_fast32_t | INT_FAST32_TYPE |
| int_fast64_t | INT_FAST64_TYPE |
| uint_fast8_t | UINT_FAST8_TYPE |
| uint_fast16_t | UINT_FAST16_TYPE |
| uint_fast32_t | UINT_FAST32_TYPE |
| uint_fast64_t | UINT_FAST64_TYPE |
| intptr_t | INTPTR_TYPE |
| uintptr_t | UINTPTR_TYPE |
GCC 定义了一批表示数据类型最大/小值的宏,如下表所示:
| 数据类型 | 数据类型最大值宏 |
|---|---|
| signed char | SCHAR_MAX |
| wchar_t | WCHAR_MAX |
| signed short | SHRT_MAX |
| signed int | INT_MAX |
| signed long | LONG_MAX |
| signed long long | LONG_LONG_MAX |
| wint_t | WINT_MAX |
| size_t | SIZE_MAX |
| ptrdiff_t | PTRDIFF_MAX |
| intmax_t | INTMAX_MAX |
| uintmax_t | UINTMAX_MAX |
| sig_atomic_t | SIG_ATOMIC_MAX |
| int8_t | INT8_MAX |
| int16_t | INT16_MAX |
| int32_t | INT32_MAX |
| int64_t | INT64_MAX |
| uint8_t | UINT8_MAX |
| uint16_t | UINT16_MAX |
| uint32_t | UINT32_MAX |
| uint64_t | UINT64_MAX |
| int_least8_t | INT_LEAST8_MAX |
| int_least16_t | INT_LEAST16_MAX |
| int_least32_t | INT_LEAST32_MAX |
| int_least64_t | INT_LEAST64_MAX |
| uint_least8_t | UINT_LEAST8_MAX |
| uint_least16_t | UINT_LEAST16_MAX |
| uint_least32_t | UINT_LEAST32_MAX |
| uint_least64_t | UINT_LEAST64_MAX |
| int_fast8_t | INT_FAST8_MAX |
| int_fast16_t | INT_FAST16_MAX |
| int_fast32_t | INT_FAST32_MAX |
| int_fast64_t | INT_FAST64_MAX |
| uint_fast8_t | UINT_FAST8_MAX |
| uint_fast16_t | UINT_FAST16_MAX |
| uint_fast32_t | UINT_FAST32_MAX |
| uint_fast64_t | UINT_FAST64_MAX |
| intptr_t | INTPTR_MAX |
| uintptr_t | UINTPTR_MAX |
| wchar_t | WCHAR_MIN |
| wint_t | WINT_MIN |
| sig_atomic_t | SIG_ATOMIC_MIN |
GCC 还定义了一批表示数据类型占用字节数的宏,如下表所示:
| 数据类型 | 数据类型占用字节数宏 |
|---|---|
| int | SIZEOF_INT |
| long | SIZEOF_LONG |
| long long | SIZEOF_LONG_LONG |
| short | SIZEOF_SHORT |
| void * | SIZEOF_POINTER |
| float | SIZEOF_FLOAT |
| double | SIZEOF_DOUBLE |
| long double | SIZEOF_LONG_DOUBLE |
| size_t | SIZEOF_SIZE_T |
| wchar_t | SIZEOF_WCHAR_T |
| wint_t | SIZEOF_WINT_T |
| ptrdiff_t | SIZEOF_PTRDIFF_T |
【注】在某些特定系统上,GCC 如果没有提供 stdint.h 头文件,则上表中的某些数据类型对应的宏可能就未被定义。
3. 查看 编译器 所有内置宏定义
注意:windows平台需要打开 git bash 终端才行
查看当前系统下的 GCC 所有内置宏定义
gcc -dM -E - < /dev/null
查看当前系统下的 G++ 所有内置宏定义
g++ -dM -E -x c++ - < /dev/null
4. 系统内置宏定义
对于某些特定系统本身内置的一些宏,GCC 提供和其等价的宏,等价宏的命名在原有宏名称基础上,首尾加上一个或多个下划线,保证首尾下划线数均为 2。比如 Unix 系统的 unix 宏,则 GCC 提供 __unix__ 宏;而对于 _mpis 宏,则 GCC 提供 __mips__ 宏。
5. 内置操作符宏定义
C++ 定义了 11 个操作符宏,如下表所示:
| 操作符 | 操作符宏 |
|---|---|
| && | and |
| &= | and_eq |
| & | bitand |
| | | bitor |
| ~ | compl |
| ! | not |
| != | not_eq |
| || | or |
| |= | or_eq |
| ^ | xor |
| ^= | xor_eq |
如果想要在 C 语言中使用 C++ 中定义的这 11 个操作符宏,可以引入 iso646.h 头文件。
windows平台特有宏
1、WIN32宏
在 Win32 配置下,WIN32 在“项目属性-C/C++-预处理器-预处理器定义”里声明了,而在 x64 配置下,这个常量并不在项目预定义列表中。这是否说明可以根据 WIN32 来判断是否在 x64 平台呢?不。在 Windows SDK 的 minwindef.h 下第 37 行有如下定义:
#ifndef WIN32
#define WIN32
#endif
即是说,只要包含了 Windows.h,那么 WIN32 常量是肯定定义了的,所以不能用于判断平台环境。但是如果在预处理定义里删掉 WIN32,又不包含 Windows.h,那么 WIN32 未定义
2、_WIN32,_WIN64
_WIN32 和 _WIN64,这两个比较特别,没有任何显式定义。在 Windows.h 里没有,在“项目属性-C/C++-预处理器-预处理器定义”下也没有。根据 MSDN,这是由编译器(ml.exe/ml64.exe)内部定义的。具体描述是
_WIN32:Defined for applications for Win32 and Win64. Always defined.
_WIN64:Defined for applications for Win64.
3、总结
WIN32宏 --只要包含了 Windows.h,那么 WIN32 常量是肯定定义了的,所以不能用于判断平台环境
_WIN32 --32位和64位程序都有,且总是定义的.
_WIN64 --只有64位程序才有
常用代码:
(1)判断是不是windows平台
#if _WIN32 || WIN32 //windows平台
...
#else
...
#endif
(2)判断是不是64位环境还是32位
#ifdef _WIN64
#ifdef _DEBUG
#pragma comment(lib, "*x64d.lib")
#else
#pragma comment(lib, "*x64r.lib")
#endif
#else
#ifdef _DEBUG
#pragma comment(lib, "*x86d.lib")
#else
#pragma comment(lib, "*x86r.lib")
#endif
#endif
错误案例
#ifdef WIN32
#ifdef _DEBUG
#pragma comment(lib, "*x86d.lib")
#else
#pragma comment(lib, "*x86r.lib")
#endif
#else
#ifdef _DEBUG
#pragma comment(lib, "*x64d.lib")
#else
#pragma comment(lib, "*x64r.lib")
#endif
#endif

浙公网安备 33010602011771号