6

I have a C++ learning demo here:

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';

The compiler warnings:

image

Can anyone explain this to me? How to fix it?

K.F
  • 97
  • 4
  • 3
    I'm not an expert, but I suspect this is likely related to https://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points, if not a duplicate – Tas Jul 27 '18 at 03:10
  • 4
    Better to paste warning straightly for searching. – dao leno Jul 27 '18 at 06:30
  • Split the cout statements in several lines to force execution order. –  Jul 27 '18 at 07:04
  • @Tas can you point out where in that Q/A it covers the code in this question? – M.M Jul 27 '18 at 07:24
  • @M.M you're clearly more of an expert here, and I upvoted your answer, but the part in the first answer that talks about the order of evaluation and an object having its value accessed only once in a single statement, and I thought the `printf` code demonstrated this same problem. I may be wrong ofc, but when I saw this question and read through that I assumed it was very related if not the answer, but I didn't attempt to close this only link what I thought might be useful – Tas Jul 27 '18 at 10:03
  • 1
    Sigh, reopened. The alleged duplicate does not cover this code , pretty sick of low-effort users hastily closing things because there are a couple of words in common with another question – M.M Jul 27 '18 at 19:11

3 Answers3

8

Since C++17 the code is correct.

Prior to C++17 the evaluation of operands of a << chain was unsequenced, so the code caused undefined behaviour.

The compiler warning suggests you are not compiling in C++17 mode. To fix it you could either:

  • Compile in C++17 mode, or
  • Separate the << chain into multiple cout << statements where there is not x and ++x within the same statement.

Note: As of now, all versions of g++ seem to be bugged and not implement these sequencing requirements correctly, see this thread for some more examples. The warnings can be seen as indicating the compiler bug; they are not just bogus warnings.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Why does with `-std=c++17 -Wall` still show warning? Shouldn't it be suppressed by `-std=c++17`? Or `-Wall` can warn suppressed warning even though it is suppressed by the standard? => [compiler explorer](https://godbolt.org/g/JzobCb) – sandthorn Jul 27 '18 at 06:18
  • 4
    @sandthorn There is no such thing as "suppressed by the standard". The standard allows any implementation to warn for any code for any reason. The quality of the diagnostics does not affect conformance. That said, if a warning is giving out incorrect information it may be worth reporting as a bug. The implementors do want to provide good diagnostics. –  Jul 27 '18 at 06:42
  • @hvd It turns out that GCC doesn't warn, even with `std=c++11`, unless with `-Wall`. While clang warns "no matter what". => [compiler explorer](https://godbolt.org/g/qkgCyE) – sandthorn Jul 27 '18 at 06:44
  • 2
    agree that a bug should be reported for clang 6 and gcc 8.1 -Wall bogus warnings – M.M Jul 27 '18 at 07:23
1

You re having undefined behavior in lines 18, 19, 20. Cause of the result of executing the line will be different depending on whether ptr or ++ptr is evaluated first.

bobra
  • 615
  • 3
  • 18
  • While I agree this is probably the right answer, your answer could be improved by explaining why it's not guaranteed that one will be evaluated before the other, is this a compiler thing or dictated by the standard, and what can be done to fix it? – Tas Jul 27 '18 at 03:18
  • So how to fix it? – K.F Jul 27 '18 at 03:53
  • @K.F It turns out that GCC doesn't warn, even with `std=c++11`, unless with `-Wall`. While clang warns "no matter what". => [compiler explorer](https://godbolt.org/g/qkgCyE) So, in case of clang, you must provide option `-Wunsequenced` to suppress it. – sandthorn Jul 27 '18 at 06:50
  • @sandthorn In case of clang, it seems the -Wunsequenced option cannot suppress the warning. Have you tried that? – K.F Jul 28 '18 at 10:58
  • @K.F My bad and decency of time-limited comment fixing policy. It should be `-Wno-unsequenced`. Sorry. – sandthorn Jul 28 '18 at 11:00
1

According to C++ Standard Draft Paper N4762 (2018-07-07) on page 68 in section § 6.8.1/10

( or [intro.execution]/10 on eel.is website here )

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.


For statement

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

that means c++ compiler can not guarantee that static_cast<void*>(cptr) will be evaluated before ++cptr on the right because they are all operands on the same statement.

So you can force their sequential order of execution simply by ordering them in ordered and separated statements.

For example :

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

[ compiler explorer ]


Update

As M.M's answer states that c++17 now guarantees operand evaluation sequence of <<

It turns out that GCC 8.1 doesn't warn, even with std=c++11, unless with -Wall and always warns with -Wall

While clang 6.0 warns "no matter what".

[ compiler explorer ]

So, as well as -std=c++17, you must also provide option -Wno-unsequenced to suppress it :

  • if you are on clang 6.0
  • if you are on gcc 8.1 with -Wall
sandthorn
  • 2,770
  • 1
  • 15
  • 59
  • @M.M I added "also" but you may edit mine if still ambiguous. Or do you suggest that both compiler still not guarantee `<<` operand evaluation sequence with `-std=c++17` because the warning are still there? – sandthorn Jul 27 '18 at 07:25
  • @M.M I changed wording from "other than" to "as well as" – sandthorn Jul 27 '18 at 07:30