TIME_STAT_1
和TIME_STAT_2
两个宏的目的是想定义一个不重复的变量名(根据行号),但是只有TIME_STAT_1
能够达到目的
以下是 TIME_STAT_1
和 TIME_STAT_2
两种宏展开的详细流程解析,配合图示说明关键差异:
#define CONCAT(x, y) x##y
#define TIME_STAT_LOGIC_1(node, num) TimeRecorder CONCAT(node, num)(#node);
#define TIME_STAT_1(node) TIME_STAT_LOGIC_1(node, __LINE__);
#define TIME_STAT_LOGIC_2(node, num) TimeRecorder node##num(#node);
#define TIME_STAT_2(node) TIME_STAT_LOGIC_2(node, __LINE__);
42
行TIME_STAT_1(foo)
和 TIME_STAT_2(bar)
TIME_STAT_1
展开流程graph TD
A[TIME_STAT_1(foo)] --> B[展开外层宏 TIME_STAT_LOGIC_1(foo, __LINE__)]
B --> C[参数替换: node=foo, num=42 (__LINE__先展开)]
C --> D[展开CONCAT宏: CONCAT(foo, 42)]
D --> E[拼接符号: foo##42 → foo42]
E --> F[最终展开: TimeRecorder foo42("foo");]
分步解析:
TIME_STAT_1(foo) → TIME_STAT_LOGIC_1(foo, __LINE__)
__LINE__
先被展开为 42
TIME_STAT_LOGIC_1(foo, 42)
TimeRecorder CONCAT(foo, 42)(#foo);
CONCAT(foo, 42) → foo##42 → foo42
#foo → "foo"
TimeRecorder foo42("foo");
TIME_STAT_2
展开流程graph TD
A[TIME_STAT_2(bar)] --> B[展开外层宏 TIME_STAT_LOGIC_2(bar, __LINE__)]
B --> C[直接拼接符号: bar##__LINE__]
C --> D[生成中间符号: bar__LINE__]
D --> E[__LINE__未展开,保留字面量]
E --> F[最终展开: TimeRecorder bar__LINE__("bar");]
分步解析:
TIME_STAT_2(bar) → TIME_STAT_LOGIC_2(bar, __LINE__)
bar
和 __LINE__
字面量bar__LINE__
(此时 __LINE__
未被展开)#bar → "bar"
TimeRecorder bar__LINE__("bar"); // 行号未展开!
# 预处理结果对比(假设调用位置为第42行)
+---------------------+-------------------------------+
| TIME_STAT_1 | TIME_STAT_2 |
+---------------------+-------------------------------+
| TimeRecorder foo42 | TimeRecorder bar__LINE__ |
| ("foo"); | ("bar"); |
+---------------------+-------------------------------+
| __LINE__先展开 | __LINE__未展开 |
| 正确生成唯一标识符 | 生成错误字面量 |
+---------------------+-------------------------------+
阶段 | TIME_STAT_1 |
TIME_STAT_2 |
---|---|---|
参数展开时机 | 先展开 __LINE__ 再拼接 |
先执行 ## 拼接,阻止展开 |
标准依据 | 参数优先展开规则 | ## 操作符优先级更高 |
调试技巧 | gcc -E 可见分步展开过程 |
预处理结果直接显示 __LINE__ |
TIME_STAT_1
:安全可靠,符合预期TIME_STAT_2
:存在设计缺陷实际开发中应优先选择 TIME_STAT_1
的方式
【技术人的鼓励】❤️ 如果这篇文章对您有帮助,欢迎点击打赏按钮支持博主!您的鼓励是我持续输出优质技术内容的动力,哪怕只是1元也足以让我感受到这份珍贵的认可。