C++: 'cout << pointer << ++pointer' generates a compiler warning
Asked Answered
H

3

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?

Hoffmann answered 27/7, 2018 at 3:1 Comment(6)
I'm not an expert, but I suspect this is likely related to #4176828, if not a duplicateClosemouthed
Better to paste warning straightly for searching.Halifax
Split the cout statements in several lines to force execution order.Labarum
@Closemouthed can you point out where in that Q/A it covers the code in this question?Tartaglia
@Tartaglia 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 usefulClosemouthed
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 questionTartaglia
T
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.

Tartaglia answered 27/7, 2018 at 6:3 Comment(4)
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 explorerDespatch
@Despatch 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.Flamsteed
@hvd It turns out that GCC doesn't warn, even with std=c++11, unless with -Wall. While clang warns "no matter what". => compiler explorerDespatch
agree that a bug should be reported for clang 6 and gcc 8.1 -Wall bogus warningsTartaglia
S
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.

Saritasarkaria answered 27/7, 2018 at 3:13 Comment(5)
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?Closemouthed
So how to fix it?Hoffmann
@Hoffmann It turns out that GCC doesn't warn, even with std=c++11, unless with -Wall. While clang warns "no matter what". => compiler explorer So, in case of clang, you must provide option -Wunsequenced to suppress it.Despatch
@Despatch In case of clang, it seems the -Wunsequenced option cannot suppress the warning. Have you tried that?Hoffmann
@Hoffmann My bad and decency of time-limited comment fixing policy. It should be -Wno-unsequenced. Sorry.Despatch
D
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
Despatch answered 27/7, 2018 at 5:55 Comment(2)
@Tartaglia 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?Despatch
@Tartaglia I changed wording from "other than" to "as well as"Despatch

© 2022 - 2024 — McMap. All rights reserved.