在 _Generic 宏中传递不兼容的指针类型 [英] Incompatible pointer types passing in _Generic macro

查看:18
本文介绍了在 _Generic 宏中传递不兼容的指针类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码生成 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆