泛型表达式中的副作用

时间:2014-12-20 20:29:03

标签: c generics c11

我正在使用新的_Generic关键字进行一些实验,并偶然发现了一个有关多个评估的特殊情况。请参阅以下内容:

#include <stdio.h>

#define write_char(c) _Generic(c, char: putchar, const char: putchar)(c)

int main(void)
{
    const char *s = "foo";

    write_char(*s++);
    write_char(*s++);
    write_char(*s++);

    putchar('\n');
}

编译好并使用GCC产生预期结果:

$ gcc -std=c11 -Wall plusplus.c -o plusplus
$ ./plusplus 
foo

另一方面,Clang输出了一个很大的鸣喇叭警告:

$ clang -std=c11 plusplus.c -o plusplus
plusplus.c:9:18: warning: multiple unsequenced modifications to 's'
      [-Wunsequenced]
    write_char(*s++);
                 ^~
plusplus.c:3:32: note: expanded from macro 'write_char'
#define write_char(c) _Generic(c, char: putchar, const char: putchar)(c)

...

然而结果如预期:

$ ./plusplus
foo

我查了the draft of the standard,其中说(在PDF的第97页):

  

不评估通用选择的控制表达式。

这似乎可以准确地解决宏中的副作用问题(例如MINMAX)。

现在,我可以放心地忽略Clang的警告,还是我错了?

2 个答案:

答案 0 :(得分:3)

正如我在评论中提到的那样,你在Clangs主干中修复了错误两周后发布了这个问题。见修订版rL223266(2014年12月3日)。修正案包含在Clang 3.6中。

  

现在,我可以放心地忽略Clang的警告,还是我错了?

我们已经知道你是对的,所以这里有一种方法可以忽略Clang中的pragma 未来:

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsequenced"

write_char(*s++);

#pragma clang diagnostic pop

要在每次使用宏时不重复,可以将_Pragma放在其正文中:

#define write_char(c) \
    _Pragma("clang diagnostic push") \
    _Pragma("clang diagnostic ignored \"-Wunsequenced\"") \
    _Generic(c, char: putchar, const char: putchar)(c) \
    _Pragma("clang diagnostic pop")

答案 1 :(得分:0)

这似乎是一个错误。从clang 3.6开始,它已经解决,如here所示。