多行宏添加注释的错误(如果不想因为脑子局部性注意力而导致浪费一下午+一晚上时间,请好好看)

C/C++

Posted by Bruce Lee on 2024-05-09

多行宏添加注释的错误(如果不想因为脑子局部性注意力而导致浪费一下午时间,请好好看)

正确的示例用法

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
#define some_macro(x, y) \
((x) + \
(y) )

int main(int argc, char** argv)
{
printf("use some_macro: %d\n", some_macro(5, 1));
return 0;
}

输出:

1
use some_macro: 6

预编译文件内容:

1
2
3
4
5
6
# 6 "test1.c"
int main(int argc, char** argv)
{
printf("use some_macro: %d\n", ((5) + (1) ));
return 0;
}

一眼真理:正如我们经常做的那样,在每一后的最后使用反斜杠,然后跟回车,让回车键转意.

如果这样呢?

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#define some_macro(x, y) \
//这个宏是做加法
((x) + \
(y) )

int main(int argc, char** argv)
{
printf("use some_macro: %d\n", some_macro(5, 1));
return 0;
}

编译报错:

1
2
3
4
test2.c:4:13: error: expected ‘)’ before ‘+’ token
4 | ((x) + \
| ^~
| )

查看一下预编译文件:

1
2
3
4
5
6
7
8
9
# 4 "test2.c"
((x) +
(y) )

int main(int argc, char** argv)
{
printf("use some_macro: %d\n", );
return 0;
}

看出:#define定义了一个空的宏(什么也没有), 在printf函数中,后面的参数是空的.
然后原来注释后的宏的代码被留下来了.

添加注释如://这个宏是做加法,后面不加反斜杆,则预编译器会认为宏的定义到此为止,后面代码会被忽略.
后面的:

1
2
((x) +
(y) )

编译器是无法认出这样的语法的.故报错.

如果再这样呢?

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#define some_macro(x, y) \
//这个宏是做加法 \
((x) + \
(y) )

int main(int argc, char** argv)
{
printf("use some_macro: %d\n", some_macro(5, 1));
return 0;
}

在注释后面也加上反斜杠,这样就不会错了吧(聪明如你)

编译器给的信:

1
2
3
test3.c:9:56: error: expected expression before ‘)’ token
9 | printf("use some_macro: %d\n", some_macro(5, 1));
|

隐藏的地狱级bug(这个报错并没有报在定义宏的位置,而是在调用宏的位置),后文有讲:遭受的地狱级排错.

注意,单行注释是不对的.因为逻辑推理:我们做的一切都是让宏的代码全在一行里,如果我们在中间添加的单行注释的预编译器语法,那么就会变成这样:

1
#define some_macro(x, y) //这个宏是做加法 ((x) + (y) )

理想中应该是这样:

1
#define some_macro(x, y) ((x) + (y) )

前者当然是错误的,会将后面的宏代码全部当作注释的一部分.

预编译器给的信:

1
2
3
4
5
6
# 7 "test3.c"
int main(int argc, char** argv)
{
printf("use some_macro: %d\n", );
return 0;
}

果然,注释后面的宏代码全部当作注释的一部分消失了.

如果最后这样写怎么样?

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>
#define some_macro(x, y) \
/*这个宏是做加法*/ \
((x) + \
(y) )

int main(int argc, char** argv)
{
printf("use some_macro: %d\n", some_macro(5, 1));
return 0;
}

这样做就是正确的,你完全可以按照上一个问题分析出原因.

我曾经犯下过如此错误

在工程项目中,会用到很多的宏,进行代码的简写.大篇大篇的多行宏让我看花了眼.
导致我在这样的代码中间增加了一行注释:

1
2
3
4
5
6
7
8
9
10
#define INSTPAT(pattern, ...) do { \
uint64_t key, mask, shift; \
pattern_decode(pattern, STRLEN(pattern), &key, &mask, &shift); \
if ((((uint64_t)INSTPAT_INST(s) >> shift) & mask) == key) { \
//指令模式匹配正确时,执行该基本块 \
Assert(shift == 0, "shift don't equit 0!"); \
INSTPAT_MATCH(s, ##__VA_ARGS__); \
goto *(__instpat_end); \
} \
} while (0)

我甚至还在注释的后面加了反斜杠.这个编译之后报错是不会报行数的(因为报的行数不是错误的地方).而是报宏的调用处,以及一些显而易见是正确的但是显示是错误的错误.(额,我蒙了,浪费了一下午+一晚上时间去排错)


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. All the images used in the blog are my original works or AI works, if you want to take it,don't hesitate. Thank you !