【发布时间】:2021-07-08 22:17:39
【问题描述】:
我有一些代码使用 _Generic 根据参数的类型调度函数。我不明白 gcc 生成的警告。
使用gcc main.c编译
#include <stdio.h>
#define FOOBAR(x) _Generic((x), \
int *: foo(x), \
long *: bar(x) \
)
void foo(int* x) {
printf("foo\n");
}
void bar(long* y) {
printf("bar\n");
}
int main() {
int a = 1111;
long b = 2222;
FOOBAR(&a);
FOOBAR(&b);
}
现在,此代码确实可以编译,并且 _Generic 可以按预期工作,即“foo”出现,然后出现“bar”。但是,编译器(gcc 和 clang)会生成一个奇怪的警告,看起来像是将 _Generic 的参数匹配到错误的行:
main.c: In function ‘main’:
main.c:20:12: warning: passing argument 1 of ‘bar’ from incompatible pointer type [-Wincompatible-pointer-types]
20 | FOOBAR(&a);
| ^~
| |
| int *
main.c:5:15: note: in definition of macro ‘FOOBAR’
5 | long *: bar(x) \
| ^
main.c:12:16: note: expected ‘long int *’ but argument is of type ‘int *’
12 | void bar(long* y) {
| ~~~~~~^
main.c:21:12: warning: passing argument 1 of ‘foo’ from incompatible pointer type [-Wincompatible-pointer-types]
21 | FOOBAR(&b);
| ^~
| |
| long int *
main.c:4:14: note: in definition of macro ‘FOOBAR’
4 | int *: foo(x), \
| ^
main.c:8:15: note: expected ‘int *’ but argument is of type ‘long int *’
8 | void foo(int* x) {
| ~~~~~^
生成两个警告,每个 FOOBAR 一个。它似乎正在将 &a(它是 int *)传递给需要长 * 的 bar,反之亦然 &b。
(注释掉其中一个 FOOBAR,只看到一个不兼容的指针错误。)
为什么 gcc 会警告我 _Generic 将其 arg 分派给错误的函数?
我知道这通常不是人们使用 _Generic 的方式,即参数列表通常在 _Generic() 之外。但是我有一些用例可以分派到采用不同数量参数的函数。
【问题讨论】:
-
你为什么不直接用
-E预处理文件,看看你的宏扩展成什么? -
@Useless:你试过了吗?这不是很有帮助,因为
_Generic是在编译时处理的,而不是预处理时处理的,预处理器只会通过它。 -
请注意,
_Generic不是宏——它是一个主要的表达式。见§6.5.1.1 Generic selection。 -
哦,这绝对有道理——我只是没有真正使用过 C11,问题使用了“宏”这个词。