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

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

问题描述

以下code产生2警告其在问题的标题描述。

 的#include<&stdio.h中GT;静态无效_print_f(浮点* F){printf的(浮动:%F \\ n,* F);}
静态无效_print_i为(int * I){printf的(INT数:%d \\ n,* I);}#定义打印(NUM)_Generic((NUM),\\
    INT *:_print_i(NUM),\\
    浮*:_print_f(NUM))
INT主要(无效)
{
    打印((放大器;(INT){10}));
    打印((及(浮动){} 10.f));    返回0;
}

输出:

  INT:10
飘:10.000000

我知道,这个宏可以写成如下所示:

 的#define打印(NUM)_Generic((NUM),\\
    INT *:_print_i,\\
    浮*:_print_f)(NUM)

和在这种情况下,将不会有任何的警告,但是我的例子是一个伪段我写证明的问题。在我真正的code碱基我选择了前者的解决方案,因为其他一些默认,但类型的具体参数需要传递给所选的功能。

所以,问题是: 即使宏,它应该工作,输出正是我期望的,生成的警告为什么


标记和环境:

  / *的Mac OS X 10.9.4
   (基于LLVM 3.4svn)苹果LLVM 5.1版(铛-503.0.40)* /
CC -Wall -v -g -std = C11 -fmacro-回溯极限= 0 -I在/ usr /本地/包括
   -c -o建立的/ tmp / main.o中的main.c


UPDATE1:

我忘了贴全追踪!这里是第一个:

 的main.c:39:11:警告:不兼容的指针类型传递'诠释*'
类型为浮动*'的参数[-Wincompatible指针类型]
    打印((放大器;(INT){10}));
          ^ ~~~~~~~~~~~
main.c中:31:23:注意:从宏观打印扩大
    浮*:_print_f(NUM))
                      ^
main.c中:26:29:注意:传递参数,参数'F'在这里
静态无效_print_f(浮点* F){printf的(浮动:%F \\ n,* F);}
                            ^

这是第二个:

 的main.c:40:11:警告:不兼容的指针类型传递浮动*'
以类型的参数'诠释*'[-Wincompatible指针类型]
    打印((及(浮动){} 10.f));
          ^ ~~~~~~~~~~~~~~~
main.c中:30:23:注意:从宏观打印扩大
    INT *:_print_i(NUM),\\
                      ^
main.c中:27:27:注意:传递参数,参数'我'在这里
静态无效_print_i为(int * I){printf的(INT数:%d \\ n,* I);}
                          ^


UPDATE2:

修复这个bug的开发人员来说,这里是一个丑陋的一块变通办法的静音警告,如果在assoc命令列表的所有按键均类型,将工作,或都是指针类型;如果类型和指针类型的键也将失败:

  / * HACK:重新铸造指针静音警告* /
#定义打印(NUM)_Generic((NUM),\\
    INT *:_print_i(为(int *)NUM),\\
    浮*:_print_f((浮点*)NUM))


解决方案

这是不是在铿锵的错误,但不幸的是什么C11标准要求。一个 _Generic 小学前pression的所有分支必须是一个有效的前pressions,因此任何情况下都有效。只有一个分支将永远被评估的事实,是不相关的此

您替代版本是C11预见的情况,因为这:选择的功能(而不是评估呼叫)作为类型通用前pression的结果,以及应用该函数的参数

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\n", *f);}
static void _print_i(int *i)  {printf("int   : %d\n", *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;
}

OUTPUT:

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?


Flags and Environment:

/* 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


Update1:

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\n", *f);}
                            ^

And here is the second one:

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\n", *i);}
                          ^


Update2:

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))

解决方案

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.

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天全站免登陆