c - 泛型表达式的副作用

标签 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 页):

The controlling expression of a generic selection is not evaluated.

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

现在,我可以安全地忽略 Clang 的警告吗?还是我错了?

最佳答案

正如我在评论中提到的,您在 Clangs 主干中修复错误大约两周后发布了问题。请参阅修订 rL223266 (2014 年 12 月 3 日)。该修复包含在 Clang 3.6 中。

Now, can I safely ignore Clang's warning, or am I wrong?

我们已经知道你是对的,所以这里有一种方法可以忽略 Clang 中的编译指示 future :

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

write_char(*s++);

#pragma clang diagnostic pop

为了不在每次使用宏时都重复它,您可以输入 _Pragma在它的 body 里:

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

关于c - 泛型表达式的副作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27584048/

相关文章:

c - 用户在数组中插入了多少个元素?

c - 解释一下这个图像对象中的 "scanline pointer array"?

C11 GCCthreads.h 未找到?

c - 为什么我不能在开关选择结构中使用 "goto default;"或 "goto case x;"?

c - c99 中与类型无关的 memcpy

java - 从套接字中逐行读取

c - 我如何告诉 cmake 执行这两个步骤来使用 winpcap?

c# - 是否有一种(优雅的)解决方案可以在方法中进一步约束泛型类型参数?

java - 在列表中添加假类型时没有异常

java - 关于 Java 中通用数组的创建