【问题标题】:Side effects in generic expressions泛型表达式的副作用
【发布时间】:2014-12-20 20:29:03
【问题描述】:

我正在用新的 _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 的警告,还是我错了?

【问题讨论】:

  • 听起来您应该向 Clang 开发团队报告问题,而不是忽略它。您可能是第一个遇到该问题的人。当你写putchar(*s++) 时会发生什么?这也会产生警告吗?大概不会。
  • 我认为你在 clang 中发现了一个错误!
  • @PascalCuoq,不,它不相关。那里观察到的警告是有道理的。这不是,在给定的代码中没有对++ 的未排序评估。
  • @doukremt,我不知道您是否已经提交了错误(在错误跟踪器中看不到它),但是在尝试了您的示例并且没有看到任何错误之后,我查看了 Clang 中的提交历史记录并从 2014 年 12 月 3 日找到this commit。所以它实际上是一个错误,并且已经修复。
  • @xaizek 供未来读者参考,您可以将其发布为问题的正确答案。

标签: c generics c11


【解决方案1】:

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

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

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-25
      • 1970-01-01
      • 1970-01-01
      • 2020-10-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-16
      相关资源
      最近更新 更多