C ++:'cout <<指针<< ++ pointer'生成编译器警告

时间:2018-07-27 03:01:19

标签: c++ compiler-warnings cout

我在这里有一个C ++学习演示:

char c = 'M';
short s = 10;
long l = 1002;
char * cptr = &c;
short * sptr = &s;
long * lptr = &l;
cout << "cptr:\t" << static_cast<void*>(cptr) << '\n';
cout << "cptr++:\t" << static_cast<void*>(++cptr) << '\n';
cout << "sptr:\t" << sptr << '\n';
cout << "sptr++:\t" << ++sptr << '\n';
cout << "lptr:\t" << lptr << '\n';
cout << "lptr++:\t" << ++lptr << '\n';

cout << c << '\t' << static_cast<void*>(cptr) << '\t' << static_cast<void*>(++cptr) << '\n';
cout << s << '\t' << sptr << '\t' << ++sptr << '\n';
cout<< l << '\t' << lptr << '\t'<< ++lptr << '\n';

编译器警告:

image

有人可以向我解释吗?如何解决?

3 个答案:

答案 0 :(得分:9)

Since C++17 the code is correct

Prior to C++17<<链的操作数的求值是未排序的,因此代码导致未定义的行为。

编译器警告提示您未在C ++ 17模式下进行编译。要解决此问题,您可以:

  • 以C ++ 17模式编译,或者
  • <<链分成多个cout <<语句,其中同一语句中没有x++x

注意:到目前为止,所有g ++版本似乎都存在漏洞,无法正确实现这些排序要求,有关更多示例,请参见this thread。这些警告可以视为指示编译器错误;它们不只是虚假的警告。

答案 1 :(得分:2)

根据C ++标准草案N4762(2018-07-07)第68页§6.8.1 / 10

<罢工>

(或 eel.is 网站here上的 [intro.execution] / 10

  

除非另有说明,否则对单个运算符的操作数和各个表达式的子表达式的求值是无序列的。


要声明

cout << c << '\t' << static_cast<void*>(cptr) << '\t' << static_cast<void*>(++cptr) << '\n';

这意味着c ++编译器不能不能保证static_cast<void*>(cptr)将在右边的++cptr之前进行求值,因为它们都是相同的相同的操作数声明。

因此,您可以简单地通过按有序和分隔的语句对它们进行排序来强制执行它们的顺序执行。

例如:

cout << c << '\t' << static_cast<void*>(cptr) << '\t'; cout << static_cast<void*>(++cptr) << '\n';

[ compiler explorer ]


更新

M.M的回答指出,c ++ 17现在可以保证<<的操作数求值顺序

事实证明,即使使用std=c++11也不会警告GCC 8.1,除非使用-Wall并始终使用-Wall警告

当clang 6.0警告“无论如何”时。

[ compiler explorer ]

因此,与-std=c++17一样,您还必须提供选项-Wno-unsequenced来禁止它:

  • 如果您使用的是clang 6.0
  • 如果您使用-Wall在gcc 8.1上

答案 2 :(得分:1)

您在18, 19, 20行中有未定义的行为。根据首先评估ptr还是++ptr,执行该行的结果的原因会有所不同。