在 _Generic 宏中传递不兼容的指针类型 [英] Incompatible pointer types passing in _Generic macro
问题描述
以下代码生成 2 个警告,在问题标题中进行了描述.
The following code generates 2 warnings which are described in the question's title.
#include <stdio.h>
static void _print_f(float *f){printf("float : %f
", *f);}
static void _print_i(int *i) {printf("int : %d
", *i);}
#define print(num) _Generic((num),
int* : _print_i(num),
float* : _print_f(num))
int main(void)
{
print((&(int){10}));
print((&(float){10.f}));
return 0;
}
输出:
int : 10
float : 10.000000
我知道,这个宏可以写成这样:
I know, this macro could be written like the following:
#define print(num) _Generic((num),
int* : _print_i,
float* : _print_f)(num)
在这种情况下,不会有任何警告,但是我的示例是一个虚拟片段,我写它来演示这个问题.在我的真实代码库中,我选择了前一种解决方案,因为需要将一些其他默认"但类型特定的参数传递给所选函数.
and in that case, there won't be any warnings, however my example is a dummy snippet which I wrote to demonstrate the problem. In my real code base I chose the former solution, because some other "default" but type specific arguments needs to be passed to the selected function.
所以问题是:即使宏正常工作,并且输出正是我所期望的,为什么会生成警告?
So the question is: Even if the macro is working as it should, and the output is exactly what I expect, why are the warnings generated?
标志和环境:
/* Mac OS X 10.9.4
Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn) */
cc -Wall -v -g -std=c11 -fmacro-backtrace-limit=0 -I/usr/local/include
-c -o build/tmp/main.o main.c
<小时>
更新1:
我忘了粘贴完整的回溯!这是第一个:
I forgot to paste the full traceback! Here is the first one:
main.c:39:11: warning: incompatible pointer types passing 'int *'
to parameter of type 'float *' [-Wincompatible-pointer-types]
print((&(int){10}));
^~~~~~~~~~~~
main.c:31:23: note: expanded from macro 'print'
float* : _print_f(num))
^
main.c:26:29: note: passing argument to parameter 'f' here
static void _print_f(float *f){printf("float : %f
", *f);}
^
这是第二个:
main.c:40:11: warning: incompatible pointer types passing 'float *'
to parameter of type 'int *' [-Wincompatible-pointer-types]
print((&(float){10.f}));
^~~~~~~~~~~~~~~~
main.c:30:23: note: expanded from macro 'print'
int* : _print_i(num),
^
main.c:27:27: note: passing argument to parameter 'i' here
static void _print_i(int *i) {printf("int : %d
", *i);}
^
<小时>
更新 2:
在 clang
的开发者修复这个错误之前,这里有一个丑陋的解决方法来静音警告,如果 assoc-list 中的所有键都是类型,或者都是指向类型;如果类型和指向类型的指针也在键中,则会失败:
Until the developers of clang
fix this bug, here is an ugly piece of workaround to mute the warnings, which will work if all keys in the assoc-list are types, OR all are pointers to types; and will fail if types AND pointers to types are in the keys too:
/* HACK: re-casting pointers to mute warnings */
#define print(num) _Generic((num),
int* : _print_i((int*)num),
float* : _print_f((float*)num))
推荐答案
这不是 clang 的 bug,但不幸的是 C11 标准要求的._Generic
主表达式的所有分支都必须是有效的表达式,因此在所有情况下都有效.只有一个分支会被评估这一事实与此无关.
This is not a bug in clang, but unfortunately what the C11 standard requires. All branches of a _Generic
primary expression must be a valid expressions, and thus valid under all circumstances. The fact that only one of the branches will ever be evaluated, is not related to this.
您的替代版本是 C11 对以下情况的预见:选择函数(而不是评估的调用)作为类型泛型表达式的结果,并将该函数应用于参数.
Your alternative version is what C11 foresees for situations as this: chose the function (and not the evaluated call) as a result of the type generic expression, and apply that function to the arguments.
这篇关于在 _Generic 宏中传递不兼容的指针类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!