If the programmer makes assumptions that are broken, then havoc will
occur. Other than that, your paragraph makes no sense to me.
> Also note that the behavior is different with optimization (release
> build) and without (which can be the case for a debug build), with no
> apparent problem for the debug build.
If you are using different options for releases from those for debugging
(other than early testing, or perhaps special case debugging) then your
development process is broken. Test what you ship, ship what you test.
>
> So the gcc optimization yields
>
> (1) broken assumptions, perhaps thereby causing a nuclear attack on
> one's own position, and
Let's be 100% clear here - it is the programmer's assumptions that are
broken. The compiler is correct.
So gcc's optimisation demonstrates that people who do not understand the
undefined behaviour of signed overflow in C and C++ are not qualified to
write nuclear attack code. I think we already knew that.
>
> (2) possibly/probably active sabotage of debugging efforts to fix that,
> with no problem apparent in the debugging
Are you /really/ suggesting that gcc optimises code according to the C
and C++ standards, and according to normal programmer's understandings,
as some sort of method of deliberately causing /you/ trouble during
debugging of invalid code?
>
> which nastiness IMHO is a pretty steep cost for avoiding one or two
> machine code instructions in a rare special case.
>
Yes, those evil gcc programmers are scheming away trying to find new
ways to annoy you.
>
>> We are talking about /undefined behaviour/ here.
>
> Yes, that's what this sub-thread is about and has been about, a special
> case of formal UB.
It is not "a special case" - it is one of many cases of undefined behaviour.
>
> Good observation.
>
> And with well-defined signed arithmetic -- modular -- one would have
> avoided that UB.
The standards committee could also have defined "1/0" to mean "send the
developer some flowers" - then it would have avoided another sort of
undefined behaviour. It might be tough to implement, but it would be
well defined.
We have already covered the fact that modular behaviour of signed
integers is counter-intuitive, and is at best one of many possible
choices for defining behaviour. Giving signed overflow a defined
behaviour will not make incorrect code correct - if you have code that
relies on a signed overflow, your code is broken.
So since modular signed integer behaviour does not help any programmer
(except perhaps people moving from Java to C++ and who like to write
awkward code), and it hinders valid optimisations that turn up as a
result of inlining, templates, and constant propagation, I think the gcc
developers have done a good job here.
And if you or anyone else insists on denying the reality of C's
undefined behaviour, then I recommend learning to enable warnings in gcc
so that the compiler will tell you when you are being stupid (at least,
in this particular case).
>
> And one would then therefore also avoid the broken assumption, and
> therefore also the resulting self-immolation or other unplanned effect.
>
> As mentioned earlier, and I think you agreed with that, formal UB is not
> a carte blanche for the compiler to do unreasonable things, such as
> removing the function call in "x = foo( i++, i++ )", or removing whole
> loops and, except when the programmer tries to find out what's going on
> by debugging, executing "if" bodies when their conditions don't hold.
Yes, undefined behaviour /is/ a carte blanche for the compiler to do
such things. It is very simple to avoid writing undefined behaviour -
learn to use the programming language you are working with. As an aid,
learn to use the tools you are working with - gcc will warn about lots
of undefined behaviour.
I don't care if "x = foo(i++, i++)" gets removed, or translated into
"format c:". I would not write it - nor would anyone else with even a
basic understanding of C - other than perhaps to test the compiler. And
even if I /did/ write it as a typo, the compiler would tell me it was a
bad idea.
>
>
>> If you want to check
>> reality, you will have to do /far/ better than a single check of a
>> couple of compilers on one platform.
>>
>> Give me test results from a dozen code cases in each of C and C++,
>> compiled with multiple compilers (at least MSVC, gcc, llvm and Intel),
>> with several versions, on at least Windows and Linux, each with 32-bit
>> and 64-bit targets, and each with a wide variety of command line
>> switches. Show me that /everything/ except gcc /always/ treats signed
>> overflow as modular, and I start to consider that there might be a
>> pattern.
>>
>> Then I'll send you to check perhaps 40 different embedded compilers for
>> 30 different targets.
>
> I believe those requirements are far more stringent than the reality
> checking before the decision to make std::string's buffer guaranteed
> contiguous, at the committee's meeting at Lillehammer in 2005.
>
> However, while your requirements are unrealistic it's unclear what they
> are requirements for.
You claim that gcc is somehow perverse and awkward about optimising
unsigned overflow as undefined behaviour. If you want to be taken
seriously in that claim, show us that a substantial proportion of other
compilers have a different behaviour. I think that is only reasonable.
>
> Some others and I are discussing the issue of whether it might be a good
> idea (or not) to make signed arithmetic formally modular. As I've shown
> you by linking to Google Groups' archive, this is an old discussion in
> clc++. I referred to a thread 9 years ago, but it goes even further
> back: most arguments are well known; regarding this issue you have
> contributed nothing new so far.
And fortunately the powers that be in the C and C++ world have done the
right thing - ignored you. It is a silly idea.
>
> But your requirements statement above indicates that you are discussing
> whether gcc is alone in its treatment of signed overflow.
>
> I don't know, but I do think you're alone in discussing that.
You started this whole thread by claiming that gcc was perverse and
intentionally awkward by its treatment of signed overflow!
"In practice it's modular on all modern systems, but at least one
compiler (namely g++) uses the formal UB for overflow, supporting
archaic systems, as an excuse to do rather inconvenient things, like
"optimizations". You will most proabbly stop g++ from doing that by
using the option "-fwrapv". This informs that compiler that you do want
the practical and efficient machine code level modular arithmetic
behaviour, two's complement form."
>
>
>> Alternatively, I'll settle for quotations from the documentation for
>> said compilers guaranteeing this behaviour, if you don't want to test
>> them all.
>
> I'll just note now that with guaranteed modular signed arithmetic, one
> would more probably add an assertion about e.g. "x+b > 0".
Marvellous - you want to give your own specific definition to the
undefined behaviour, and to make it work safely you want to add extra
source code (with no logical meaning) that will (at least sometimes,
depending on what the compiler can figure out at compile time) mean more
run-time code.
>
> Such simple assertions would then not only most probably catch the
> invalid actual argument, but the added knowledge could in many cases be
> used by the compiler to optimize the code.
>
Sometimes assertions can be useful for that sort of thing - such as for
checking that your values are within the limits of defined behaviour.
> Of course, instead of CHANGING the semantics of existing types, one
> could introduce new types, perhaps via a header like <stdint.h>.
>
> In passing, new types are also IMO a good solution for gcc's problems
> with IEEE conformance (it's of two minds because semantics changes with
> options, and so it reports false guarantees via numeric_limits).
>
> So, the general idea is a win-win-win: getting rid of UB, detecting bugs
> up front, getting optimization without counter-intuitive cleverness --
> and incidentally getting rgw same behavior for release and debug
> builds of the code, which I think is very much desirable.
>
Learn to use "-Wall". That gets rid of this particular undefined
behaviour, along with many other types of undefined behaviour or other
code errors.
Learn that "optimising" is something a compiler can /always/ do,
regardless of the flags you give it.
Learn to use a proper development process. Then you will not have
"release" and "debug" builds, and therefore no inconsistencies no matter
how badly you understand the concept of undefined behaviour.