Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Good way to write integer overflow checks?

359 views
Skip to first unread message

Alf P. Steinbach

unread,
Nov 9, 2013, 10:28:29 AM11/9/13
to
This code is in support of some API functionality:


[code]
inline
auto can_inflate( gdi::Rect const& r, int const dx, int const dy )
-> bool
{
CPPX_XASSERT( INT_MIN/2 < dx && dx < INT_MAX/2 );
CPPX_XASSERT( INT_MIN/2 < dy && dy < INT_MAX/2 );

typedef unsigned long Unsigned_long;
auto const msb = ULONG_MAX - (ULONG_MAX >> 1);
return
(r.left & msb) == ((Unsigned_long( r.left ) - dx) & msb) &&
(r.top & msb) == ((Unsigned_long( r.top ) - dy) & msb) &&
(r.right & msb) == ((Unsigned_long( r.right ) + dx) & msb) &&
(r.bottom & msb) == ((Unsigned_long( r.bottom ) + dy) & msb);
}
[/code]


Can this be written in an even gooder way, for bestest possible code?

Disclaimer: the code has not been tested or even called.


Cheers,

- Alf

Leigh Johnston

unread,
Nov 9, 2013, 10:58:50 AM11/9/13
to
Again why do you write:

auto foo() -> bool {}

instead of just:

bool foo() {}

?

The latter is less typing and clearer than the former.

The C++11 trailing-return-type feature does have valid use-cases (e.g.
templates) but the above is not one of them. "C++11 consistency" is not
a valid excuse for what you are doing as ideally one has to be
consistent with the billions of lines or pre-existing pre-C++11 C++ code
also.

Again I think the real reason you do this is that you are anally retentive.

/Leigh

Leigh Johnston

unread,
Nov 9, 2013, 11:09:15 AM11/9/13
to
On 09/11/2013 15:28, Alf P. Steinbach wrote:
Comparing using <= might be more efficient than comparing using == with
two bitmask AND operations; check what code your optimizer produces.

/Leigh


Leigh Johnston

unread,
Nov 9, 2013, 11:23:41 AM11/9/13
to
On 09/11/2013 16:09, Leigh Johnston wrote:
> On 09/11/2013 15:28, Alf P. Steinbach wrote:
>> This code is in support of some API functionality:
>>
>>
>> [code]
>> inline
>> auto can_inflate( gdi::Rect const& r, int const dx, int const dy )
>> -> bool
>> {
>> CPPX_XASSERT( INT_MIN/2 < dx && dx < INT_MAX/2 );
>> CPPX_XASSERT( INT_MIN/2 < dy && dy < INT_MAX/2 );
>>
>> typedef unsigned long Unsigned_long;
>> auto const msb = ULONG_MAX - (ULONG_MAX >> 1);

You go to the trouble of aliasing a type with typedef then proceed to
not use it on the following line using instead what you seem to think is
a panacea (auto keyword)?

It is a shame that C++11 seems to be turning competent C++ programmers
back into n00bish C++ programmers.

Another bugbear: overuse of lambdas. Ever heard of functional
decomposition? I am sure you were aware of it once.

/Leigh

Victor Bazarov

unread,
Nov 9, 2013, 2:26:33 PM11/9/13
to
What is the code supposed to do? Are you checking if the size of 'r' is
not going to under- or overflow if you add dx and dy to it? Isn't this
the usual way to check if (b+a) is not going to overflow:

if (INT_MAX - b > a) // a+b will NOT overflow
..
?

V
--
I do not respond to top-posted replies, please don't ask

Alf P. Steinbach

unread,
Nov 9, 2013, 4:00:42 PM11/9/13
to
On 09.11.2013 20:26, Victor Bazarov wrote:
> On 11/9/2013 10:28 AM, Alf P. Steinbach wrote:
>> This code is in support of some API functionality:
>>
>>
>> [code]
>> inline
>> auto can_inflate( gdi::Rect const& r, int const dx, int const dy )
>> -> bool
>> {
>> CPPX_XASSERT( INT_MIN/2 < dx && dx < INT_MAX/2 );
>> CPPX_XASSERT( INT_MIN/2 < dy && dy < INT_MAX/2 );
>>
>> typedef unsigned long Unsigned_long;
>> auto const msb = ULONG_MAX - (ULONG_MAX >> 1);
>> return
>> (r.left & msb) == ((Unsigned_long( r.left ) - dx) & msb) &&
>> (r.top & msb) == ((Unsigned_long( r.top ) - dy) & msb) &&
>> (r.right & msb) == ((Unsigned_long( r.right ) + dx) & msb) &&
>> (r.bottom & msb) == ((Unsigned_long( r.bottom ) + dy) & msb);
>> }
>> [/code]
>>
>>
>> Can this be written in an even gooder way, for bestest possible code?
>>
>> Disclaimer: the code has not been tested or even called.
>
> What is the code supposed to do? Are you checking if the size of 'r' is
> not going to under- or overflow if you add dx and dy to it?

Yes.


> Isn't this the usual way to check if (b+a) is not going to overflow:
>
> if (INT_MAX - b > a) // a+b will NOT overflow

Don't know, but that expression has formally Undefined Behavior when b
is a negative signed integer, since then the checking itself overflows.

So, at least if one's not going to rely on two's complement form
wrap-around (g++ can be made to trap on that), I /think/ it would yield
more verbose code, possibly also more complicated?


Cheers,

- Alf

Ian Collins

unread,
Nov 9, 2013, 4:14:44 PM11/9/13
to
Alf P. Steinbach wrote:
> This code is in support of some API functionality:
>
>
> [code]
> inline
> auto can_inflate( gdi::Rect const& r, int const dx, int const dy )
> -> bool

Alf,

Why do you insist on using this form rather than the sorter, more
conventional form?

--
Ian Collins

Alf P. Steinbach

unread,
Nov 9, 2013, 5:09:34 PM11/9/13
to
On 09.11.2013 22:14, Ian Collins wrote:
> Alf P. Steinbach wrote:
>> This code is in support of some API functionality:
>>
>> [code]
>> inline
>> auto can_inflate( gdi::Rect const& r, int const dx, int const dy )
>> -> bool
>
> Why do you insist on using this form rather than the sorter, more
> conventional form?

Uhm, the word "insist" incorrectly indicates some kind of opposition to
the adoption of `auto`. ;-)

Anyway, there are many good reasons, but for me the most important is a
consistent visual layout:

* function name at fixed place.
* return type visually separated.

Which means that the human eye finds it much easier to just scan through
the code to find a name or note the names, or inspect return types, with
no to read and analyze the text.

Second in importance for me, there is the matter of consistency. Instead
of using two different declaration syntaxes for the same kind of
function, with the choice depending on whether one needs some `decltype`
for the function result, I just use just ...

* one single declaration syntax for all non-void functions.

This is the main reason for using the syntax also for `main`.

I use the old form for "void" functions, consistent with the above
points, and with much the same rationale as for the `procedure` versus
`function` distinction in Pascal. That is, a declaration syntax
distinction between routines that produce expression values, versus
those that don't. I'm not sure how USEFUL that distinction is, but it
feels right.


Cheers & hth.,

- Alf

PS: For readers who are unfamiliar with C++11-stuff, here's Scott Meyers
with a short blog posting about `decltype` and `auto`: <url:
http://scottmeyers.blogspot.no/2013/07/when-decltype-meets-auto.html>.

Victor Bazarov

unread,
Nov 9, 2013, 5:33:00 PM11/9/13
to
Yes, but that is easy to check itself, is it not?

> since then the checking itself overflows.

It won't if you don't do *that particular checking* for negative b, now,
will it?

> So, at least if one's not going to rely on two's complement form
> wrap-around (g++ can be made to trap on that), I /think/ it would yield
> more verbose code, possibly also more complicated?

You mean, more difficult to read and understand than your fiddling with
the bits? Wrap it into smaller functions, name them appropriately, and
you shouldn't have any problem... Or don't.<shrug>

If you wanted an argument, you should have said so. Although,
admittedly, upon re-reading your message, I ought to guessed as much
from the use of "gooder" and "bestest"... You got me.

Sam

unread,
Nov 9, 2013, 8:34:40 PM11/9/13
to
Yes, it can be. A more generic algorithm, for any signed int type:

template<typename signed_int_t>
signed_int_t add_with_overflow_check(signed_int_t a, signed_int_t b)
{
signed_int_t c=a+b;

if (b > 0)
{
if (c < a)
do_whatever_you_want_when_you_overflow();
}
else
{
if (c > a)
do_whatever_you_want_when_you_overflow();
}

return c;
}

Your C++ homework assignment consists of three parts:

1. Explain why the above code works

2. Implement a version for any unsigned int type

3. Use template specialization and std::numeric_limits to implement a
template that will work for any signed or unsigned int type


Leigh Johnston

unread,
Nov 9, 2013, 8:49:01 PM11/9/13
to
0. Explain why the above code is undefined behaviour.

/Leigh

Alf P. Steinbach

unread,
Nov 10, 2013, 1:15:35 AM11/10/13
to
Hm, that's a tough one!

I agree that something in this direction is how things ideally should
work, in part because I think that the optimizations that are enabled by
the formal signed overflow UB are both marginal, often radically
unexpected, and generally easy to achieve by more explicit means.

However, with the C++ standard as it is (as of C++11) this code is not
formally portable, and worse, it /should not be/ practically portable to
environments where "-ftrapv" is used with the g++ compiler. So, I tried
your code with MinGW g++ 4.7.2, and the code appears to detect the
overflow even with the "-ftrapv" option specified, where the overflow
should be trapped. Apparently that is a COMPILER BUG. :-(


[code]
#include <stdexcept>

void do_whatever_you_want_when_you_overflow()
{
throw std::runtime_error( "integer overflow");
}

template<typename signed_int_t>
signed_int_t add_with_overflow_check(signed_int_t a, signed_int_t b)
{
signed_int_t c=a+b;

if (b > 0)
{
if (c < a)
do_whatever_you_want_when_you_overflow();
}
else
{
if (c > a)
do_whatever_you_want_when_you_overflow();
}

return c;
}

#include <iostream>
#include <stdlib.h>
using namespace std;

auto main() -> int
{
try
{
int const x = add_with_overflow_check<int>( int(-1/2u), 1 );
cout << x << endl;
return EXIT_SUCCESS;
}
catch( exception const& x )
{
cerr << "!" << x.what() << endl;
}
catch( ... )
{
cerr << "!unknown exception." << endl;
}
return EXIT_FAILURE;
}
[/code]

[example]
[D:\dev\test]
> version g++
g++ (GCC) 4.7.2

[D:\dev\test]
> g++ foo.cpp -fno-wrapv -ftrapv

[D:\dev\test]
> a
!integer overflow

[D:\dev\test]
> _
[/code]


Apparently the lack of any trapping here means that MinGW g++ is
UNRELIABLE in this respect, i.e. that using "-ftrapv" with g++ is not a
reliable way to catch this kind of error (in the usual cases where the
overflow is an error, not intentional) in debug builds.


> 2. Implement a version for any unsigned int type

I'm sorry, but that question doesn't make much sense to me.

If you look at the code I posted originally, it shows one way to
leverage the well-defined'ness of unsigned arithmetic to detect overflow
reliably -- if not as elegant as I'd wished it to be, which is what I
asked about.

So, what's the problem there?


> 3. Use template specialization and std::numeric_limits to implement a
> template that will work for any signed or unsigned int type

I think the apparent MinGW compiler bug for question (1) has to be dealt
with first, lest we get into compiler make and version sniffing. Then,
to make use of such a template practical, I think one would need
suitable integer wrapper types with no implicit narrowing, test suites
that demonstrate convincingly that this introduces no bugs and no added
inefficiency, and examples that demonstrate that one would not easily
use it incorrectly. This seems to be a pretty big effort?


Cheers,

- Alf

Öö Tiib

unread,
Nov 10, 2013, 11:39:52 AM11/10/13
to
On Saturday, 9 November 2013 17:28:29 UTC+2, Alf P. Steinbach wrote:
> This code is in support of some API functionality:
> [code]
> inline
> auto can_inflate( gdi::Rect const& r, int const dx, int const dy )
> -> bool
> {
> CPPX_XASSERT( INT_MIN/2 < dx && dx < INT_MAX/2 );
> CPPX_XASSERT( INT_MIN/2 < dy && dy < INT_MAX/2 );
>
> typedef unsigned long Unsigned_long;
> auto const msb = ULONG_MAX - (ULONG_MAX >> 1);
> return
> (r.left & msb) == ((Unsigned_long( r.left ) - dx) & msb) &&
> (r.top & msb) == ((Unsigned_long( r.top ) - dy) & msb) &&
> (r.right & msb) == ((Unsigned_long( r.right ) + dx) & msb) &&
> (r.bottom & msb) == ((Unsigned_long( r.bottom ) + dy) & msb);
> }
> [/code]
>
> Can this be written in an even gooder way, for bestest possible code?

Depends what is "goodness". I would write something like:

template<typename T>
inline
bool can_add(T const a, T const b)
{
return a < 0 ? std::numeric_limits<T>::min() - a =< b
: std::numeric_limits<T>::max() - a >= b;
}

inline
bool can_inflate( gdi::Rect const& r, int const dx, int const dy )
{
return can_add(r.left, -dx)
&& can_add(r.top, -dy)
&& can_add(r.right, dx)
&& can_add(r.bottom, dy);
}

Typed into post and did not test, sorry.

Alf P. Steinbach

unread,
Nov 10, 2013, 12:00:48 PM11/10/13
to
It's more clear code. :-)

But involves a branch for each test.

I wonder if the compiler can optimize that away, and if not, if one can
somehow reduce the whole thing to two branches (which appears minimum?).


Cheers, & thanks,

- Alf

Leigh Johnston

unread,
Nov 10, 2013, 2:46:44 PM11/10/13
to
On 10/11/2013 06:15, Alf P. Steinbach wrote:

> #include <iostream>
> #include <stdlib.h>
> using namespace std;

"using namespace std;" is both amateurish and lame.

>
> auto main() -> int

Have you not heard? It is:

int main()

C++11 has certainly made YOU regress.

/Leigh

Öö Tiib

unread,
Nov 10, 2013, 5:08:22 PM11/10/13
to
On Sunday, 10 November 2013 19:00:48 UTC+2, Alf P. Steinbach wrote:
That they usually consider one aspect of goodness.

> But involves a branch for each test.
>
> I wonder if the compiler can optimize that away, and if not, if one can
> somehow reduce the whole thing to two branches (which appears minimum?).

Maybe split the problem from other place then:

template<typename T>
inline
bool can_enwiden(T const low, T const high, T delta)
{
return delta < 0 ? (std::numeric_limits<T>::min() - delta <= high
&& std::numeric_limits<T>::max() + delta >= low)
: (std::numeric_limits<T>::max() - delta >= high
&& std::numeric_limits<T>::min() + delta <= low);
}

I feel more worried if the checks done are sufficient. For example does
the invariant of that 'gdi::Rect' really allow the turned around rectangles?
I mean where 'r.left > r.right'? Current checks tell that one 'can_inflate'
into such rectangles.

Alf P. Steinbach

unread,
Nov 10, 2013, 6:37:39 PM11/10/13
to
On 10.11.2013 23:08, 嘱 Tiib wrote:
> On Sunday, 10 November 2013 19:00:48 UTC+2, Alf P. Steinbach wrote:
I didn't understand that at first glance, but it's pretty cool. ;-)


> I feel more worried if the checks done are sufficient. For example does
> the invariant of that 'gdi::Rect' really allow the turned around rectangles?
> I mean where 'r.left > r.right'? Current checks tell that one 'can_inflate'
> into such rectangles.

Yes, it's the Windows API's RECT, and testing this, at least as of
Window 7 it allows rectangles to be turned around. It has to allow
"turned around" rectangles as such because they're used with various
coordinate systems. But the API could conceivably refuse to invert a
rectangle via the inflation function (called InflateRect), since
presumably a given rectangle should make sense for some given coordinate
system, and then turning it around (so to speak) could reasonably fail
as meaningless. It's not documented, AFAICS. But it just inflated with
negative delta, turning the rectangle inside out.


Cheers,

- Alf

David Brown

unread,
Nov 11, 2013, 3:29:29 AM11/11/13
to
If you know (or have previously checked) that dx and/or dy are
non-negative, then there is no problem.

>
> So, at least if one's not going to rely on two's complement form
> wrap-around (g++ can be made to trap on that), I /think/ it would yield
> more verbose code, possibly also more complicated?
>

Didn't you learn /anything/ from the thread about undefined behaviour on
signed overflow? Because signed overflow is undefined, the compiler can
generate /better/ code than it could if it had to support wrap-around
behaviour. It will certainly /never/ generate worse code.

Stop guessing (you are not "/thinking/", you are guessing) and try it
out. Look at the generated assembly on the target in question. Profile
it and see if it is too slow. Otherwise any attempt to improve the code
is a waste because you don't know that the code is a problem, and can't
check or measure any improvements.


David Brown

unread,
Nov 11, 2013, 4:27:25 AM11/11/13
to
It is not "tough" - as you have noticed yourself, it does /not/ work.

>
> I agree that something in this direction is how things ideally should
> work, in part because I think that the optimizations that are enabled by
> the formal signed overflow UB are both marginal, often radically
> unexpected, and generally easy to achieve by more explicit means.

It does not matter what you think in this matter - it was established
long ago that you are wrong, and that neither C or C++ standards groups,
not compiler implementers, nor most developers follow your ideas here.
You are, of course, welcome to your opinions and can use "-fwrapv" if
you want - but it won't change the rest of the C++ world.

>
> However, with the C++ standard as it is (as of C++11) this code is not
> formally portable, and worse, it /should not be/ practically portable to
> environments where "-ftrapv" is used with the g++ compiler.

The code is portable. It is undefined behaviour on all platforms.
(With some compilers, and some flag options, it happens to give a
particular type of behaviour - but /any/ behaviour is consistent with
/undefined/ behaviour.) As it stands, the code asks for nasal daemons -
it might happen to give a check for signed overflow in some
circumstances, but that's just luck.


> So, I tried
> your code with MinGW g++ 4.7.2, and the code appears to detect the
> overflow even with the "-ftrapv" option specified, where the overflow
> should be trapped. Apparently that is a COMPILER BUG. :-(
>

In the great majority of cases where people think they have found a
"COMPILER BUG", they are wrong. This is one of them. It is, IMHO, a
documentation "bug" - the gcc manual could be much clearer here.

The "-ftrapv" option does not stop signed overflow from being undefined
behaviour. This means that you are not guaranteed traps on overflows -
but you /might/ get them. It is dependent on many things, including the
types of optimisation, the target, the knowledge the compiler has (i.e.,
does it /know/ there is always an overflow, or never an overflow), etc.

At best, -ftrapv is a debugging aid - it can lead to significantly worse
code, but help spot some types of program error.


Oh, and "int(-1/2u)" is undefined behaviour.
-ftrapv has never been "reliable" in this way - it is a debugging aid
sometimes, but that's all.

David Brown

unread,
Nov 11, 2013, 4:44:24 AM11/11/13
to
If you want to know what code the compiler generates, try it and see.
Look at the generated assembly. If you can't read the assembly, then
you are not qualified to judge the quality of the generated code - trust
your compiler, because it knows more than you do.

gcc (and other compilers) are pretty good at eliminating branch
instructions, as long as you enable reasonably powerful optimisations
(-O is, I think, sufficient on gcc - but -O2 is the norm for code when
you are interested in performance).

Anyway, do you /know/ that branches are costly here? On some cpus they
are slow and lead to pipeline flushes or stalls. But on modern x86-64
cpus, branches like this can often be sorted out early in the execution
path or handled by speculative execution, and become free. What did
your profiling runs tell you about how much effect this code has on the
program's run times?

Also make sure you are using the appropriate "-mtune" and "-march"
parameters to get the best code for the particular target you are using.


This all sounds to me like premature optimisation, which as we know
(thanks to Knuth) is the root of all evil. So if you are asking about
the generated code for performance reasons, you are doing things badly
wrong - but if it is out of interest or perfectionism and for your own
enjoyment, then that's fine. Like many evils, premature optimisation is
fun :-)




Alf P. Steinbach

unread,
Nov 11, 2013, 6:31:41 AM11/11/13
to
I'm sorry but what you write sounds like trolling. It's certainly
idiocy, it's certainly more about your guessing about people's thoughts
than the technical, and your assertions are extremely dishonest.

I.e. you're a liar.

Plink.

- Alf

Alf P. Steinbach

unread,
Nov 11, 2013, 6:35:07 AM11/11/13
to
On 11.11.2013 10:27, David Brown wrote:
>
[snipped lots of idiocy, then:]
>
> Oh, and "int(-1/2u)" is undefined behaviour.

No, unsigned arithmetic is well-defined.

I think I plinked you earlier, are you posting under a new e-mail address?

Plink.


- ALf


Alf P. Steinbach

unread,
Nov 11, 2013, 6:37:46 AM11/11/13
to
I've already replied to earlier postings of yours in this thread.

You have demonstrated general incompetence, reasoning disability,
dishonesty and trolling.

Plink.


- Alf

David Brown

unread,
Nov 11, 2013, 7:34:23 AM11/11/13
to
On 11/11/13 12:35, Alf P. Steinbach wrote:
> On 11.11.2013 10:27, David Brown wrote:
>>
> [snipped lots of idiocy, then:]
>>
>> Oh, and "int(-1/2u)" is undefined behaviour.
>
> No, unsigned arithmetic is well-defined.

AFAIUI, int(-1/2u) means "take the signed int -1, promote it to an
unsigned to be compatible with 2u (this promotion is UB for a negative
number), divide it by 2 (fine in unsigned), then convert it to a signed
int (fine if there is no overflow)".

Does it mean something else to you? (It's quite possible that I've got
this wrong, but I'd prefer a better reference. Certainly "unsigned
arithmetic is well-defined" is /not/ the answer.)

>
> I think I plinked you earlier, are you posting under a new e-mail address?

I have a newsreaders on two different computers, and they happen to have
slightly different email addresses. But the name is the same.

>
> Plink.
>
>
> - ALf
>
>

David Brown

unread,
Nov 11, 2013, 7:42:36 AM11/11/13
to
If you disagree with what I write, then point out the mistakes. If I am
wrong to assume you are merely guessing about compiler behaviour, then
show me the appropriate disassembly proving that you /have/ tested this
properly.

It's fine to tell me I'm rude (I'm sure there are others that will agree
with you), and it's fine to say I'm wrong (it would not be the first
time). But it is /not/ fine to accuse someone of active dishonesty and
lying without /very/ clear and specific evidence.


Victor Bazarov

unread,
Nov 11, 2013, 8:00:46 AM11/11/13
to
On 11/11/2013 7:34 AM, David Brown wrote:
> On 11/11/13 12:35, Alf P. Steinbach wrote:
>> On 11.11.2013 10:27, David Brown wrote:
>>>
>> [snipped lots of idiocy, then:]
>>>
>>> Oh, and "int(-1/2u)" is undefined behaviour.
>>
>> No, unsigned arithmetic is well-defined.
>
> AFAIUI, int(-1/2u) means "take the signed int -1, promote it to an
> unsigned to be compatible with 2u (this promotion is UB for a negative
> number),

Where did you get the UB portion of that? And it's not "promoted", it's
"converted". Promotions defined in [conv.prom] and they don't involve
'int' as the *source* type.

> divide it by 2 (fine in unsigned), then convert it to a signed
> int (fine if there is no overflow)".

"Fine" is not a definition of what's going to happen. It's
implementation-defined if the value cannot be represented in the
destination type. See [conv.integral].

> Does it mean something else to you? (It's quite possible that I've got
> this wrong, but I'd prefer a better reference. Certainly "unsigned
> arithmetic is well-defined" is /not/ the answer.)

Well, get a copy of the Standard and ask questions after reading the
relevant sections of it.

>[..]

David Brown

unread,
Nov 11, 2013, 8:45:57 AM11/11/13
to
On 11/11/13 14:00, Victor Bazarov wrote:
> On 11/11/2013 7:34 AM, David Brown wrote:
>> On 11/11/13 12:35, Alf P. Steinbach wrote:
>>> On 11.11.2013 10:27, David Brown wrote:
>>>>
>>> [snipped lots of idiocy, then:]
>>>>
>>>> Oh, and "int(-1/2u)" is undefined behaviour.
>>>
>>> No, unsigned arithmetic is well-defined.
>>
>> AFAIUI, int(-1/2u) means "take the signed int -1, promote it to an
>> unsigned to be compatible with 2u (this promotion is UB for a negative
>> number),
>
> Where did you get the UB portion of that? And it's not "promoted", it's
> "converted". Promotions defined in [conv.prom] and they don't involve
> 'int' as the *source* type.
>

I've read the section of the standard document, and I stand corrected -
thanks.

The "-1" is converted, rather than promoted, to "unsigned int" - and
that conversion is done modulo 2^n. So the conversion of -1 to
"unsigned int" is well defined.

>> divide it by 2 (fine in unsigned), then convert it to a signed
>> int (fine if there is no overflow)".
>
> "Fine" is not a definition of what's going to happen. It's
> implementation-defined if the value cannot be represented in the
> destination type. See [conv.integral].

By "fine", I mean there is clearly defined behaviour for converting an
"unsigned int" into an "int" as long as there is no overflow - i.e., the
value can be represented identically as an "int".

If there /is/ an overflow (i.e., the value cannot be represented), then
the behaviour is implementation defined. (It is a good job I didn't say
what I thought would happen in this case - before reading the standards
closely here, I would probably have said it was "undefined behaviour".)

>
>> Does it mean something else to you? (It's quite possible that I've got
>> this wrong, but I'd prefer a better reference. Certainly "unsigned
>> arithmetic is well-defined" is /not/ the answer.)
>
> Well, get a copy of the Standard and ask questions after reading the
> relevant sections of it.
>

The obvious question to ask is, did I get it right this time?

>> [..]
>
> V

Victor Bazarov

unread,
Nov 11, 2013, 11:07:37 AM11/11/13
to
The term "overflow" as used by some other folks here is not the same as
"requires more storage than can be given". I believe the use of the
term 'overflow' relates to the situation that can be recognized by the
processor and appropriately flagged (or trapped). It is run-time
behavior (or situation), not hypothetical relationship between numbers
that exists at the compile time.

So, given that your use of the term "overflow" appears different from
Alf's, I would recommend reviewing your understanding and your previous
statements in this thread. This might help you understand the
objections Alf had to what you had said/written.

According to the standard, the behavior is implementation-defined, that
means that whatever the behavior is, it shall be documented. The result
of such conversion *may* cause overflow (IOW allow such condition to be
registered and programmatically recognized and acted upon), but it does
not *need to*, nor does it *usually* happen.

> the behaviour is implementation defined. (It is a good job I didn't say
> what I thought would happen in this case - before reading the standards
> closely here, I would probably have said it was "undefined behaviour".)
>
>>
>>> Does it mean something else to you? (It's quite possible that I've got
>>> this wrong, but I'd prefer a better reference. Certainly "unsigned
>>> arithmetic is well-defined" is /not/ the answer.)
>>
>> Well, get a copy of the Standard and ask questions after reading the
>> relevant sections of it.
>>
>
> The obvious question to ask is, did I get it right this time?

I'd say, you're getting closer.

Leigh Johnston

unread,
Nov 11, 2013, 1:47:23 PM11/11/13
to
The idiot "plink'd" you which is idiot-speak for blacklisting your
posts. He has also "plink'd" me as the guy can't handle criticism.

/Leigh

James Kanze

unread,
Nov 11, 2013, 1:54:48 PM11/11/13
to
On Saturday, 9 November 2013 22:09:34 UTC, Alf P. Steinbach wrote:
> On 09.11.2013 22:14, Ian Collins wrote:
> > Alf P. Steinbach wrote:
> >> This code is in support of some API functionality:

> >> [code]
> >> inline
> >> auto can_inflate( gdi::Rect const& r, int const dx, int const dy )
> >> -> bool

> > Why do you insist on using this form rather than the sorter, more
> > conventional form?

> Uhm, the word "insist" incorrectly indicates some kind of opposition to
> the adoption of `auto`. ;-)

> Anyway, there are many good reasons, but for me the most important is a
> consistent visual layout:

> * function name at fixed place.
> * return type visually separated.

You mean like the way I've always written function definitions:

bool
can_inflate( ... )
{
}

The function name is always at the start of the line. Has been
since I learned C. (Back then, about all we had for searching
was grep, and "grep ^can_inflate" would always get the
definition, and nothing else.)

> Which means that the human eye finds it much easier to just scan through
> the code to find a name or note the names, or inspect return types, with
> no to read and analyze the text.

You're style makes it harder to find the return type. (I never
found this a problem in Modula-2, but C++ is not Modula-2.)

--
James

James Kanze

unread,
Nov 11, 2013, 2:01:16 PM11/11/13
to
On Sunday, 10 November 2013 01:34:40 UTC, Sam wrote:
> Alf P. Steinbach writes:

[...]
> Yes, it can be. A more generic algorithm, for any signed int type:

> template<typename signed_int_t>
> signed_int_t add_with_overflow_check(signed_int_t a, signed_int_t b)
> {
> signed_int_t c=a+b;
> if (b > 0)
> {
> if (c < a)
> do_whatever_you_want_when_you_overflow();
> }
> else
> {
> if (c > a)
> do_whatever_you_want_when_you_overflow();
> }
> return c;
> }

> Your C++ homework assignment consists of three parts:

> 1. Explain why the above code works

It doesn't. Unless the undefined behavior happens to give it
the appearance of working.

To correctly check for overflow of signed integral types, you
first have to check whether the signs are the same. (If they
aren't it won't overflow.) Then check either
std::numeric_limits<int_t>::max() - a or
std::numeric_limits<int_t>::min() + a with b, depending on
whether both are negative, or both are positive.

--
James

Alf P. Steinbach

unread,
Nov 11, 2013, 2:24:57 PM11/11/13
to
On 11.11.2013 19:54, James Kanze wrote:
> On Saturday, 9 November 2013 22:09:34 UTC, Alf P. Steinbach wrote:
>> On 09.11.2013 22:14, Ian Collins wrote:
>>> Alf P. Steinbach wrote:
>>>> This code is in support of some API functionality:
>
>>>> [code]
>>>> inline
>>>> auto can_inflate( gdi::Rect const& r, int const dx, int const dy )
>>>> -> bool
>
>>> Why do you insist on using this form rather than the sorter, more
>>> conventional form?
>
>> Uhm, the word "insist" incorrectly indicates some kind of opposition to
>> the adoption of `auto`. ;-)
>
>> Anyway, there are many good reasons, but for me the most important is a
>> consistent visual layout:
>
>> * function name at fixed place.
>> * return type visually separated.
>
> You mean like the way I've always written function definitions:
>
> bool
> can_inflate( ... )
> {
> }
>
> The function name is always at the start of the line. Has been
> since I learned C. (Back then, about all we had for searching
> was grep, and "grep ^can_inflate" would always get the
> definition, and nothing else.)

No, with C++11 that style can no longer (in practice) yield a consistent
layout, since in cases where the return type depends on the argument
types one avoids a lot of complication and verbosity by using `auto`.
For details of how bad it can be see Andrei's "min max revisited"
article in DDJ (I leave it to the reader to google it). For example,
even in C++11 you can NOT simply write

template< class T >
decltype( a*b ) mul( T a, T b )
{ return a*b; }

But you can write, and since you're pragmatic you will eventually write,

template< class T >
auto mul( T a, T b )
-> decltype( a*b )
{ return a*b; }

So, your currently favorite style was good for C, to the degree that a
syntax that both the C creators and the C++ creator have described as a
"failed experiment", can be good. It was good in that sense also for
C++03. With C++11 it's IMHO just ungood, since it no longer covers all
cases and thus yields an inconsistent mix of declaration styles.


d>> Which means that the human eye finds it much easier to just scan
through
>> the code to find a name or note the names, or inspect return types, with
>> no to read and analyze the text.
>
> You're style makes it harder to find the return type. (I never
> found this a problem in Modula-2, but C++ is not Modula-2.)

Hm, I can't remember much about Modula-2 declarations.

I do remember that good old Niklaus, Praise be Upon Him, for some
inexplicable reason forced the Modula-2 programmer to use UPPERCASE
keywords. Or I think I remember that. Also it was nice with built-in
coroutine support.

Anyway... ;-)

David Brown

unread,
Nov 12, 2013, 4:02:31 AM11/12/13
to
Yes, I know what he meant by "plink" (even though I have only ever seen
it as "plonk" from other Usenet users). I've always thought it was
quite childish (like putting your fingers in your ears and saying "I'm
not listening"), except of course for the worst spammers. I suppose in
the "old days" with slow links, it might have been more important to
save bandwidth.

This is a public arena - the disagreements were in public, so I think it
is right to respond in public even after a "plonk" (or "plink"). Of
course, I'd much rather that Alf reads my posts and responds - but
that's up to him.




David Brown

unread,
Nov 12, 2013, 4:53:53 AM11/12/13
to
I am not sure that we can make such subtle distinctions about the use of
the word "overflow" - I think it is valid to use it in either sense. As
far as I can see, there is not "official" definition in the C++ standard
(correct me if I'm wrong!), and no particular grounds for fine
differentiation. To my understanding, a calculation "overflows" if it
cannot be done while keeping the natural correspondence between the
abstract idea (such as mathematical integers) and the concrete
implementation (such as a an n-bit twos-complement number). So with
16-bit integers, 30000 + 20000 overflows - regardless of whether or not
the processor flags it.

I have been trying a simple search for the term "overflow" in N3337
(approximately the C++11 standard, but conveniently available as a free
pdf). Under 1.9 "Program execution" paragraph 9, there is a discussion
about re-arranging arithmetic by associative and commutative operations
- on targets which "produce exceptions on overflow", the compiler cannot
necessarily re-arrange the arithmetic, while on targets " in which the
results of overflows are reversible" allows them.

Under chapter 5 "Expressions", we have this:

If during the evaluation of an expression, the result is not
mathematically defined or not in the range of representable values for
its type, the behavior is undefined. [ Note: most existing
implementations of C++ ignore integer overflows. Treatment of division
by zero, forming a remainder using a zero divisor, and all floating
point exceptions vary among machines, and is usually adjustable by a
library function. — end note ]


I think that suggests "overflow" means "the result is not mathematically
defined or not in the range of representable values for its type", which
is the how I have been using the term.


>
> So, given that your use of the term "overflow" appears different from
> Alf's, I would recommend reviewing your understanding and your previous
> statements in this thread. This might help you understand the
> objections Alf had to what you had said/written.

I have tried, but I don't see it. I don't think the issue of
flagging/trapping is important in the discussion (though Alf has used
"-ftrapv" with varying success in his tests). I am very open to the
idea that our disagreement was/is due to a misunderstanding on some
particular term, but I think that we do understand each other, and we
disagree. Alf thinks that signed integers should behave as module 2^n,
that this is the "natural" behaviour (following the principle of least
surprise), and that compilers should follow that even though the
standard says signed integer overflow is undefined behaviour. I think
that there is no natural behaviour for signed integer overflow, that
modulo behaviour is as surprising as any other behaviour, and that
compilers can use the "undefined behaviour" tag to allow better
optimisations.

It is unfortunate and regrettable that the argument seems to have got
suddenly out of hand with Alf's later replies to my posts - I still do
not see where his accusations come from.

>
> According to the standard, the behavior is implementation-defined, that
> means that whatever the behavior is, it shall be documented. The result
> of such conversion *may* cause overflow (IOW allow such condition to be
> registered and programmatically recognized and acted upon), but it does
> not *need to*, nor does it *usually* happen.

Yes.

tom...@gmail.com

unread,
Nov 12, 2013, 5:23:06 AM11/12/13
to
On Monday, November 11, 2013 11:37:46 AM UTC, Alf P. Steinbach wrote:
> I've already replied to earlier postings of yours in this thread.
>
> You have demonstrated general incompetence, reasoning disability,
> dishonesty and trolling.
>
> Plink.

Alf,

Please refrain from this unnecessary vitriol. This is a technical forum for the discussion of technical issues, and childish insults and finger-in-ear "la la la I can't hear you" screaming is off-topic. If you wish to "plink" someone then fine, do it, but there is no need to advertise the fact to the entire group, other than to "have the last word". Shame it's not even a real word.

Let's all stick to the matter at hand.

Thanks.

James Kanze

unread,
Nov 12, 2013, 5:45:36 AM11/12/13
to
And you said something about avoiding complication... (Of
course, in this case the return is just T, so any decltype is
simply added verbosity. I suspect you meant for a and b to
potentially have different types, however, in which case, it
sort of makes sense. If you like implicit type conversions and
unreadable code at the client level---but that too is a long
tradition, dating back to C.)

The question is: how often is something like this relevant?
Perhaps if you're writting a very low level library, but
certainly not in application code.

> But you can write, and since you're pragmatic you will eventually write,

> template< class T >
> auto mul( T a, T b )
> -> decltype( a*b )
> { return a*b; }

(Just to be clear: I think you really mean:

template< typename T1, typename T2 >
auto mul( T1 a, T2 b )
-> decltype( a * b )
{
return a * b;
}

. Otherwise, using decltype is just added verbosity.)

> So, your currently favorite style was good for C, to the degree that a
> syntax that both the C creators and the C++ creator have described as a
> "failed experiment", can be good. It was good in that sense also for
> C++03. With C++11 it's IMHO just ungood, since it no longer covers all
> cases and thus yields an inconsistent mix of declaration styles.

It's good in the same sense that && and ||, rather than "and"
and "or" are good. It's idiomatic for the language. It's what
everyone reading the language expects.

It's also good in the sense that seeing "auto" in front of
a function triggers the reaction: here's some fancy, overly
complicated template mess. Because the ubiquitous use today is
not to use "auto", unless you need it for the decltype.

That doesn't mean that in an abstract, ideal world, something
like:

FUNCTION func( ... ) -> return_type

wouldn't be better. But this isn't an abstract, ideal world;
this is C++. And the keyword "auto" is the same as for
a variable, so it doesn't add any additional information. For
the moment, all of this is new, so best practices haven't really
been established, but generally, from what I can see so far:
"auto" should be limited to variables containing "standardized"
return values of member functions, where the type of the return
value depends on the type of object the member function was
called on. E.g.

auto iter = container.begin();

For just about anything else, it's simply additional
obfuscation.

> d>> Which means that the human eye finds it much easier to just scan through
> >> the code to find a name or note the names, or inspect return types, with
> >> no to read and analyze the text.

> > You're style makes it harder to find the return type. (I never
> > found this a problem in Modula-2, but C++ is not Modula-2.)

> Hm, I can't remember much about Modula-2 declarations.

See above.

> I do remember that good old Niklaus, Praise be Upon Him, for some
> inexplicable reason forced the Modula-2 programmer to use UPPERCASE
> keywords.

Which is as it should be. Upper case stands out; keywords (like
WHILE and IF) should stand out, given the impact they have on
the meaning of the code. Upper case is less readable; the
keywords form a small, closed set, which makes them immediately
identifiable despite this.

The fact that keywords and user symbols were not distinguishable
made early C significantly harder to read. (Today, of course,
syntax highlighting solves this problem, so it's no longer
a bother.)

> Or I think I remember that. Also it was nice with built-in
> coroutine support.

Above all, it had the best model for separate compilation that
I've ever seen. (If I understand correctly, David Vandevorde's
module proposal is based, at least for the semantics, on
Modula-2's modules.)

--
James

James Kanze

unread,
Nov 12, 2013, 6:51:35 AM11/12/13
to
On Tuesday, 12 November 2013 09:53:53 UTC, David Brown wrote:
> On 11/11/13 17:07, Victor Bazarov wrote:
> >> If there /is/ an overflow (i.e., the value cannot be represented), then

> > The term "overflow" as used by some other folks here is not the same as
> > "requires more storage than can be given". I believe the use of the
> > term 'overflow' relates to the situation that can be recognized by the
> > processor and appropriately flagged (or trapped). It is run-time
> > behavior (or situation), not hypothetical relationship between numbers
> > that exists at the compile time.

> I am not sure that we can make such subtle distinctions about the use of
> the word "overflow" - I think it is valid to use it in either sense.

I don't really see two different senses. Overflow is run-time
behavior (unless it occurs in a constant expression in
pre-C++11), since whether it occurs depends on the values
involved. But I think we would agree that if the data types had
enough bits, overflow wouldn't occur. (At the hardware level,
at least with 2's complement addition, overflow is defined as
the xor of the carry into the sign bit and the carry out of the
sign bit. Hardware doesn't consider the possibility that word
size can be increased.)

> As
> far as I can see, there is not "official" definition in the C++ standard
> (correct me if I'm wrong!), and no particular grounds for fine
> differentiation. To my understanding, a calculation "overflows" if it
> cannot be done while keeping the natural correspondence between the
> abstract idea (such as mathematical integers) and the concrete
> implementation (such as a an n-bit twos-complement number). So with
> 16-bit integers, 30000 + 20000 overflows - regardless of whether or not
> the processor flags it.

Almost all processors do flag it. (IIRC, the 8080 didn't. But
that was a long time ago.) The issue is whether the generated
code pays attention to the flag.

The Intel x86 processors have a special instruction
(INTO---interrupt on overflow) precisely to make it simple to
handle. A good compiler will, at least when the proper options
are given, insert this instruction immediately after each
operation.

[...]
> > So, given that your use of the term "overflow" appears different from
> > Alf's, I would recommend reviewing your understanding and your previous
> > statements in this thread. This might help you understand the
> > objections Alf had to what you had said/written.

> I have tried, but I don't see it. I don't think the issue of
> flagging/trapping is important in the discussion (though Alf has used
> "-ftrapv" with varying success in his tests).

Trapping is one of the possible "undefined behavior". The
preferable one, although on most hardware, it has significant
performance implementations if the compiler is to achieve it.

> I am very open to the
> idea that our disagreement was/is due to a misunderstanding on some
> particular term, but I think that we do understand each other, and we
> disagree. Alf thinks that signed integers should behave as module 2^n,
> that this is the "natural" behaviour (following the principle of least
> surprise),

Least surprise for who?

> and that compilers should follow that even though the
> standard says signed integer overflow is undefined behaviour. I think
> that there is no natural behaviour for signed integer overflow, that
> modulo behaviour is as surprising as any other behaviour, and that
> compilers can use the "undefined behaviour" tag to allow better
> optimisations.

The error isn't that signed overflow isn't module; the error is
that unsigned overflow is defined. There are cases where you
want an abstraction with modulo arithmetic (e.g. calculating
hash codes), but if you're using usual arithmetic, the
"abstraction" is the set of integers (an infinit set), and if
the abstraction is violated in any manner, you want an abrupt
and fatal failure. (Afterwards, of course, it's up to you to
validate the input, so that you can't end up in such a case.)

> It is unfortunate and regrettable that the argument seems to have got
> suddenly out of hand with Alf's later replies to my posts - I still do
> not see where his accusations come from.

> > According to the standard, the behavior is implementation-defined, that
> > means that whatever the behavior is, it shall be documented. The result
> > of such conversion *may* cause overflow (IOW allow such condition to be
> > registered and programmatically recognized and acted upon), but it does
> > not *need to*, nor does it *usually* happen.

The C standard makes this much clearer: the "results" are
implementation defined, and may include an implementation
defined signal being raised.

--
James

Alf P. Steinbach

unread,
Nov 12, 2013, 7:37:04 AM11/12/13
to
On 12.11.2013 12:51, James Kanze wrote:
> On Tuesday, 12 November 2013 09:53:53 UTC, David Brown wrote:
>> Alf thinks that signed integers should behave as module 2^n,
>> that this is the "natural" behaviour (following the principle of least
>> surprise),
>
> Least surprise for who?

Please don't pay attention to David Brown. Whenever he says something
about what others mean, you can be reasonably sure that it's at best
misrepresentation, and at worst a complete fantasy. In short, he's
heavily into misrepresentation and other forms of trolling.

Regarding the C++ expression at hand, -1/2u is well-defined, casting
that back to integer will in practice not incur overflow, not even on
one complement's machines are sign and magnitude, but the holy standard
does admit implementations with rather more perverse value ranges,
simply by not considering the possibility that they could exist...

One can trust David Brown to latch on to such, and also to not
understand whatever he's read about it (he thought -1/2u was UB).


Cheers,

- Alf (pretty annoyed at himself for being suckered into DB's world)

Alf P. Steinbach

unread,
Nov 12, 2013, 8:15:32 AM11/12/13
to
That's also a possible example, with the possible advantage that it's
more obvious (has practical utility also for built-in types), and with
the drawback that it's more to type up and understand.


>
> . Otherwise, using decltype is just added verbosity.)

No, not at all. The result type does not need to be T.


>> So, your currently favorite style was good for C, to the degree that a
>> syntax that both the C creators and the C++ creator have described as a
>> "failed experiment", can be good. It was good in that sense also for
>> C++03. With C++11 it's IMHO just ungood, since it no longer covers all
>> cases and thus yields an inconsistent mix of declaration styles.
>
> It's good in the same sense that && and ||, rather than "and"
> and "or" are good. It's idiomatic for the language. It's what
> everyone reading the language expects.

Oh, standard C++ does have `and` and `or` with the usual boolean
meaning, and it's been that way since 1998.



> It's also good in the sense that seeing "auto" in front of
> a function triggers the reaction: here's some fancy, overly
> complicated template mess. Because the ubiquitous use today is
> not to use "auto", unless you need it for the decltype.

Times they are a'changing. Yes. :-)


> That doesn't mean that in an abstract, ideal world, something
> like:
>
> FUNCTION func( ... ) -> return_type
>
> wouldn't be better. But this isn't an abstract, ideal world;
> this is C++. And the keyword "auto" is the same as for
> a variable, so it doesn't add any additional information.

Oh it does.


> For the moment, all of this is new,

Well, two years old. ;-)


> so best practices haven't really been established,

Right.


> but generally, from what I can see so far:
> "auto" should be limited to variables containing "standardized"
> return values of member functions, where the type of the return
> value depends on the type of object the member function was
> called on. E.g.
>
> auto iter = container.begin();
>
> For just about anything else, it's simply additional
> obfuscation.

That's an opinion based on not using the feature, i.e. no experience,
and with no stated rationale other than a desire to keep on mainly doing
C++03 style code, which one is used to, and treating C++11 code as
exceptional.

In other words, it's a kind of brace-placement-convention argument.

But on the contrary, there are real savings by standardizing on a single
declaration form for value-returning functions -- as there always are
when one simplifies something and keep the functinality.
Amen.


Cheers, & hth.,

- Alf


David Brown

unread,
Nov 12, 2013, 8:32:10 AM11/12/13
to
On 12/11/13 12:51, James Kanze wrote:
> On Tuesday, 12 November 2013 09:53:53 UTC, David Brown wrote:
>> On 11/11/13 17:07, Victor Bazarov wrote:
>>>> If there /is/ an overflow (i.e., the value cannot be represented), then
>
>>> The term "overflow" as used by some other folks here is not the same as
>>> "requires more storage than can be given". I believe the use of the
>>> term 'overflow' relates to the situation that can be recognized by the
>>> processor and appropriately flagged (or trapped). It is run-time
>>> behavior (or situation), not hypothetical relationship between numbers
>>> that exists at the compile time.
>
>> I am not sure that we can make such subtle distinctions about the use of
>> the word "overflow" - I think it is valid to use it in either sense.
>
> I don't really see two different senses. Overflow is run-time
> behavior (unless it occurs in a constant expression in
> pre-C++11), since whether it occurs depends on the values
> involved. But I think we would agree that if the data types had
> enough bits, overflow wouldn't occur. (At the hardware level,
> at least with 2's complement addition, overflow is defined as
> the xor of the carry into the sign bit and the carry out of the
> sign bit. Hardware doesn't consider the possibility that word
> size can be increased.)

Agreed.

>
>> As
>> far as I can see, there is not "official" definition in the C++ standard
>> (correct me if I'm wrong!), and no particular grounds for fine
>> differentiation. To my understanding, a calculation "overflows" if it
>> cannot be done while keeping the natural correspondence between the
>> abstract idea (such as mathematical integers) and the concrete
>> implementation (such as a an n-bit twos-complement number). So with
>> 16-bit integers, 30000 + 20000 overflows - regardless of whether or not
>> the processor flags it.
>
> Almost all processors do flag it. (IIRC, the 8080 didn't. But
> that was a long time ago.) The issue is whether the generated
> code pays attention to the flag.

I work mostly with small processors, and I have used some that didn't
have an overflow flag. I used mostly assembly with those, though C
compilers existed for them (or "C-like language" compilers, as they did
not support all of C). One noticeable issue with these sorts of
processor is that signed comparison was expensive - without an overflow
flag, it took extra work.

But it has been a while since I used a CPU without an overflow flag
(though many don't have any kind of trap or interrupt on overflow).

>
> The Intel x86 processors have a special instruction
> (INTO---interrupt on overflow) precisely to make it simple to
> handle. A good compiler will, at least when the proper options
> are given, insert this instruction immediately after each
> operation.
>
> [...]
>>> So, given that your use of the term "overflow" appears different from
>>> Alf's, I would recommend reviewing your understanding and your previous
>>> statements in this thread. This might help you understand the
>>> objections Alf had to what you had said/written.
>
>> I have tried, but I don't see it. I don't think the issue of
>> flagging/trapping is important in the discussion (though Alf has used
>> "-ftrapv" with varying success in his tests).
>
> Trapping is one of the possible "undefined behavior". The
> preferable one, although on most hardware, it has significant
> performance implementations if the compiler is to achieve it.

Yes, if you have some sort of trapping enabled (either automatic in the
cpu in some way, or using INTO, or by compiler code that checks for
overflow and generates an exception) then you are typically going to get
bigger and slower code. Such traps limit the optimiser even if the
compiler doesn't have to generate extra code.

>
>> I am very open to the
>> idea that our disagreement was/is due to a misunderstanding on some
>> particular term, but I think that we do understand each other, and we
>> disagree. Alf thinks that signed integers should behave as module 2^n,
>> that this is the "natural" behaviour (following the principle of least
>> surprise),
>
> Least surprise for who?

For Alf, in this case (but that is part of my point - /I/ would find
modulo behaviour surprising, even though I know that it fits the
underlying hardware in most cpus).

>
>> and that compilers should follow that even though the
>> standard says signed integer overflow is undefined behaviour. I think
>> that there is no natural behaviour for signed integer overflow, that
>> modulo behaviour is as surprising as any other behaviour, and that
>> compilers can use the "undefined behaviour" tag to allow better
>> optimisations.
>
> The error isn't that signed overflow isn't module; the error is
> that unsigned overflow is defined. There are cases where you
> want an abstraction with modulo arithmetic (e.g. calculating
> hash codes), but if you're using usual arithmetic, the
> "abstraction" is the set of integers (an infinit set), and if
> the abstraction is violated in any manner, you want an abrupt
> and fatal failure. (Afterwards, of course, it's up to you to
> validate the input, so that you can't end up in such a case.)

There are many types of behaviour one could want for arithmetic (signed
and unsigned) when the result is outside the range. Modulo is one,
traps is another, saturating arithmetic is good sometimes, perhaps you
would like "errno" to be set, maybe you want the range to be increased
automatically (that would not work very well in C++ in general, but
works fine in Python and with big integer libraries), etc., - and of
course "undefined behaviour" and "implementation dependent behaviour"
are other options. I guess it's a matter of opinion and personal
preference which behaviour any given programmer would like for signed
and unsigned integers. Like it or not, in C and C++ we have "modulo"
for unsigned integers and "undefined behaviour" for signed integers -
programmers and compiler writers have to live with that, and take
advantage of that when they can.

Often when I am relying on modulo behaviour of unsigned "overflow" (it's
not really overflow, since by definition in C and C++ it is done as
modulo arithmetic), I will put things like "(a + b) & 0xffff" in my code
as a documentation that I expect modulo behaviour.

David Brown

unread,
Nov 12, 2013, 8:33:26 AM11/12/13
to
I don't know if you are reading this, Alf, but could you please just
drop this attitude? It helps no one, and I am sure I am not the only
one getting tired of it. /Nothing/ I have posted here has been
deliberate misrepresentation, lying, or intentional or active "trolling".

I make mistakes. It happens - it happens to everyone. The great thing
about Usenet is that errors get corrected by people who know more about
that particular topic. When I am shown clear evidence that I am wrong,
I accept that correction with thanks - as was the case with int(-1/2u).
Maybe I should be more careful about reading the standards before
posting and getting corrected - others have suggested that, and I'll
take that as constructive criticism for future posts.


Alf P. Steinbach

unread,
Nov 12, 2013, 9:04:10 AM11/12/13
to
On 12.11.2013 11:23, tom...@gmail.com wrote:
> On Monday, November 11, 2013 11:37:46 AM UTC, Alf P. Steinbach wrote:
>> I've already replied to earlier postings of yours in this thread.
>>
>> You have demonstrated general incompetence, reasoning disability,
>> dishonesty and trolling.
>>
>> Plink.
>
> Alf,
>
> Please refrain from this unnecessary vitriol.

In Usenet forums it's a very good idea to plink the trolls (including
you) -- or to plonk the heavy-weight trolls, to show some last respect.

When most everybody did this, the troll activity was very low, since
they knew that only newcomers read their articles.


>This is a technical forum for the discussion of technical issues, and childish insults and finger-in-ear "la la la I can't hear you" screaming is off-topic. If you wish to "plink" someone then fine, do it, but there is no need to advertise the fact to the entire group, other than to "have the last word". Shame it's not even a real word.
>
> Let's all stick to the matter at hand.
>
> Thanks.

Please just stay over in the SO troll corral?

Trollfest in clc++, argh!

Plink.


- Alf

Öö Tiib

unread,
Nov 12, 2013, 10:01:47 AM11/12/13
to
There are no such rule. Consider:

SquareMeters operator*(Meters a, Meters b);

or:

Duration operator-(TimeSpot end, TimeSpot start);

> I suspect you meant for a and b to
> potentially have different types, however, in which case, it
> sort of makes sense. If you like implicit type conversions and
> unreadable code at the client level---but that too is a long
> tradition, dating back to C.)

The operations with mixed operands are better example
indeed but something like:

template <typename T1, typename T2>
decltype( (*(T1*)0 * *(T2*)0 )
mul( T1 lhs, T2 rhs );

It looks rather ugly?

> The question is: how often is something like this relevant?
> Perhaps if you're writting a very low level library, but
> certainly not in application code.

Templates are either part of interface or low level libraries.
Various patterns of mixing and matching different types are
not so uncommon. Sometimes it is even nice to have with
one parameter because the type is too verbose:

// verbose: 'typename std::vector<T>::const_iterator'

template <typename T>
auto firstDuplicateInVector( std::vector<T> const& v )
-> decltype( v.begin() );

I also should scan some code bases for verbose or complex
return types and count. It is good idea to try to have uniform
style with as few of exceptions as possible so it is worth
trying out before deciding.

James Kanze

unread,
Nov 12, 2013, 1:47:28 PM11/12/13
to
On Tuesday, 12 November 2013 13:15:32 UTC, Alf P. Steinbach wrote:
> On 12.11.2013 11:45, James Kanze wrote:
> > On Monday, 11 November 2013 19:24:57 UTC, Alf P. Steinbach wrote:
> >> On 11.11.2013 19:54, James Kanze wrote:

> >> So, your currently favorite style was good for C, to the degree that a
> >> syntax that both the C creators and the C++ creator have described as a
> >> "failed experiment", can be good. It was good in that sense also for
> >> C++03. With C++11 it's IMHO just ungood, since it no longer covers all
> >> cases and thus yields an inconsistent mix of declaration styles.

> > It's good in the same sense that && and ||, rather than "and"
> > and "or" are good. It's idiomatic for the language. It's what
> > everyone reading the language expects.

> Oh, standard C++ does have `and` and `or` with the usual boolean
> meaning, and it's been that way since 1998.

I know. And no one uses them, and they still surprise
programmers. (They were, in fact, introduced as a work-around
for people whose keyboard didn't have a | or a &.)

> > It's also good in the sense that seeing "auto" in front of
> > a function triggers the reaction: here's some fancy, overly
> > complicated template mess. Because the ubiquitous use today is
> > not to use "auto", unless you need it for the decltype.

> Times they are a'changing. Yes. :-)

Very slowly. C++ isn't going to become Modula-2 anytime soon.

> > That doesn't mean that in an abstract, ideal world, something
> > like:

> > FUNCTION func( ... ) -> return_type

> > wouldn't be better. But this isn't an abstract, ideal world;
> > this is C++. And the keyword "auto" is the same as for
> > a variable, so it doesn't add any additional information.

> Oh it does.

What? What does it tell you, precisely.

> > For the moment, all of this is new,

> Well, two years old. ;-)

For whom? It's been less than a year that I've been able to use
a limited set of C++11, and most people I know in industry
cannot use it yet.

Whether it will change anything remains to be seen.

> > so best practices haven't really been established,

> Right.

> > but generally, from what I can see so far:
> > "auto" should be limited to variables containing "standardized"
> > return values of member functions, where the type of the return
> > value depends on the type of object the member function was
> > called on. E.g.

> > auto iter = container.begin();

> > For just about anything else, it's simply additional
> > obfuscation.

> That's an opinion based on not using the feature, i.e. no experience,

It's an opinion based on fact. In the case of variables, the
use of `auto` is pure obfuscation. It hides information
essential to understanding the code, like the types of
variables. (This is especially insideous, because some
programmers use unsigned types for numeric values.) In a very
few cases, the hidden information is obvious, and auto reduces
the verbosity enough to make it a win. But such cases are very
few.

> and with no stated rationale other than a desire to keep on mainly doing
> C++03 style code, which one is used to, and treating C++11 code as
> exceptional.

I clearly mentionned obfuscation.

> In other words, it's a kind of brace-placement-convention argument.

It's more along the lines of whether one should indent or not.

> But on the contrary, there are real savings by standardizing on a single
> declaration form for value-returning functions -- as there always are
> when one simplifies something and keep the functinality.

Yes, and such a declaration syntax exists and is already widely
used. I rather like the idea of keeping auto for the
exceptional cases: when I see auto, it tells me that someone is
more interested in playing around with new technology than in
writing code that works and that other people can understand.

--
James

Ian Collins

unread,
Nov 12, 2013, 2:10:07 PM11/12/13
to
Alf P. Steinbach wrote:
> On 12.11.2013 11:23, tom...@gmail.com wrote:
>> On Monday, November 11, 2013 11:37:46 AM UTC, Alf P. Steinbach wrote:
>>> I've already replied to earlier postings of yours in this thread.
>>>
>>> You have demonstrated general incompetence, reasoning disability,
>>> dishonesty and trolling.
>>>
>>> Plink.
>>
>> Alf,
>>
>> Please refrain from this unnecessary vitriol.
>
> In Usenet forums it's a very good idea to plink the trolls (including
> you) -- or to plonk the heavy-weight trolls, to show some last respect.

Branding someone who disagrees with a troll is poor form. You are
possibly the only regular here (and on c.l.c) who considers David Brown
to be a troll. I can't see why.

--
Ian Collins

Alf P. Steinbach

unread,
Nov 12, 2013, 2:13:44 PM11/12/13
to
On 12.11.2013 19:47, James Kanze wrote:
> On Tuesday, 12 November 2013 13:15:32 UTC, Alf P. Steinbach wrote:
>> On 12.11.2013 11:45, James Kanze wrote:
>>>
>>> For the moment, all of this is new,
>>
>> Well, two years old. ;-)
>
> For whom? It's been less than a year that I've been able to use
> a limited set of C++11, and most people I know in industry
> cannot use it yet.

g++ has supported `auto` for more than two years, since version 4.4.0 in
april 2009.

visual c++ has supported `auto` for almost exactly one year now, since
the november 2011 CTP version (version number 17.00.51025, subtract 6 to
get the ms marketing department's notion of version).

i don't know about other compilers, sorry.


[snip]
> when I see auto, it tells me that someone is
> more interested in playing around with new technology than in
> writing code that works and that other people can understand.

ouch!

i think that's an unproductive attitude.

but then, here we're into feelings and emotional drivers, which i
believe are much tied to environmental factors such as the perceived
ideas of colleagues and the main kind of code produced (in particular,
library versus app), and i can only think of purely rational, logical,
Mr. Spock-like general arguments, already tried above :-(


anyway,

cheers & hth.,

- Alf

Alf P. Steinbach

unread,
Nov 12, 2013, 2:27:19 PM11/12/13
to
On 12.11.2013 20:10, Ian Collins wrote:
>
> Branding someone who disagrees with a troll is poor form. You are
> possibly the only regular here (and on c.l.c) who considers David Brown
> to be a troll.

Possibly, but not likely. :-)

Especially, what you say is unlikely given earlier comments asking why I
continued to engage in a clearly trolling thread, when I'd already
plinked some trolls here.


> I can't see why.

Because he doesn't just disagree, he mostly misrepresents and lies.

I define "lie" as when someone actively tries to convince others of that
which he (or she) knows is false, and I only say that in public when
it's proved. Or at least I hope I do. Anyway, he lies.

I think there should be room, here and in other groups, for all honest
people, also those (e.g. Aspberger's) who appear to many others to be
trolls. And I consider it worth fighting for persons who are wrongly
excluded or made subject of ad hominem campaigns, and so I've done that
(most recently elswhere, though). But I also think that the dishonest
ones should be plinked, and, unlike the opinon here of the only person I
ever killfiled on SO, that the reasons for such actions should be made
clear. If it's lying, then IMHO it needs to be said. In clear.

Leigh Johnston

unread,
Nov 12, 2013, 3:28:11 PM11/12/13
to
If anyone else had said that you would have "plonked" them but you
realize if you also blacklist Mr Kanze you won't have anyone left to troll.

/Leigh

Scott Lurndal

unread,
Nov 12, 2013, 4:03:18 PM11/12/13
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> writes:
>On 12.11.2013 19:47, James Kanze wrote:
>> On Tuesday, 12 November 2013 13:15:32 UTC, Alf P. Steinbach wrote:
>>> On 12.11.2013 11:45, James Kanze wrote:
>>>>
>>>> For the moment, all of this is new,
>>>
>>> Well, two years old. ;-)
>>
>> For whom? It's been less than a year that I've been able to use
>> a limited set of C++11, and most people I know in industry
>> cannot use it yet.
>
>g++ has supported `auto` for more than two years, since version 4.4.0 in
>april 2009.

Why should that matter? My current C++ project needs to compile on various
versions of GCC from 4.1.2 to 4.6.4. We certainly cannot use C++11 features
and don't expect to be able to for several years to come, if then.

C++ is perfectly usable without all the C++11 cruft which, when used for
silly reasons (your -> auto return value declarations) just makes the code
harder to read and maintain. I do like the built-in threads in C++11, but
pthreads work just fine here.

And no, we cannot upgrade to newer compilers without serious and very costly
disruption. Probably won't start using C++11 until a new project is started from
scratch that has no external binary dependencies (which seems unlikely at the
moment). I suspect this is the norm for most real-world projects with more than
a single programmer on the team and more than a single C++ project within a product.

David Brown

unread,
Nov 12, 2013, 4:21:34 PM11/12/13
to
On 12/11/13 20:27, Alf P. Steinbach wrote:
> On 12.11.2013 20:10, Ian Collins wrote:
>>
>> Branding someone who disagrees with a troll is poor form. You are
>> possibly the only regular here (and on c.l.c) who considers David Brown
>> to be a troll.
>
> Possibly, but not likely. :-)
>

If there are any others who think I am a troll, or have been lying or
deliberately misrepresenting facts, then please let me know. (And if
anyone knows specifically what Alf is talking about, and can point to
where I have lied - or written something that could be interpreted as a
lie - then let me know of that too.)

Like most people, I make occasional factual errors. I accept
corrections, possibly after a discussion about /why/ I am in error. And
if it was a silly mistake that I could easily have checked, then I feel
silly about it - but no one else should feel insulted or angry as a
result, nor should they mistake an error for a lie.

Like most people, I disagree with a number of opinions held by others in
this group - that is neither an error nor a lie.

> Especially, what you say is unlikely given earlier comments asking why I
> continued to engage in a clearly trolling thread, when I'd already
> plinked some trolls here.
>
>
>> I can't see why.
>
> Because he doesn't just disagree, he mostly misrepresents and lies.
>
> I define "lie" as when someone actively tries to convince others of that
> which he (or she) knows is false, and I only say that in public when
> it's proved. Or at least I hope I do. Anyway, he lies.
>
> I think there should be room, here and in other groups, for all honest
> people, also those (e.g. Aspberger's) who appear to many others to be
> trolls. And I consider it worth fighting for persons who are wrongly
> excluded or made subject of ad hominem campaigns, and so I've done that
> (most recently elswhere, though). But I also think that the dishonest
> ones should be plinked, and, unlike the opinon here of the only person I
> ever killfiled on SO, that the reasons for such actions should be made
> clear. If it's lying, then IMHO it needs to be said. In clear.
>

I agree that /if/ someone is lying, it should be called out (though not
judged and condemned until the case is clear). And I agree that it
should be "in clear" - and yet I am at a loss to see what you are
referring to as my lies and deliberate misrepresentation. I can only
assume that something I wrote particularly irritated you in some way -
perhaps I was unreasonably sarcastic in a comment. In the interest of
peace in this newsgroup, and a return to technical discussions, I will
be happy to apologise if I have insulted you in some way.

So let me know /exactly/ what the problem is, and we can put this behind us.

Ian Collins

unread,
Nov 12, 2013, 4:50:03 PM11/12/13
to
David Brown wrote:

Something Alf should see...
I case Alf really has plonked you, he'll see this!

--
Ian Collins

Chris Vine

unread,
Nov 12, 2013, 4:51:49 PM11/12/13
to
On Tue, 12 Nov 2013 20:27:19 +0100
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
> On 12.11.2013 20:10, Ian Collins wrote:
> >
> > Branding someone who disagrees with a troll is poor form. You are
> > possibly the only regular here (and on c.l.c) who considers David
> > Brown to be a troll.
>
> Possibly, but not likely. :-)
>
> Especially, what you say is unlikely given earlier comments asking
> why I continued to engage in a clearly trolling thread, when I'd
> already plinked some trolls here.
>
>
> > I can't see why.
>
> Because he doesn't just disagree, he mostly misrepresents and lies.
>
> I define "lie" as when someone actively tries to convince others of
> that which he (or she) knows is false, and I only say that in public
> when it's proved. Or at least I hope I do. Anyway, he lies.

Obviously he doesn't know it is false. At worst he is mistaken. The
fact is that you regard anyone who disagrees with you as a troll. Or
more to the point, you brand them a troll so you can justify your
ridiculous "plink". And then, to make yourself feel better about it,
you then brand them a liar.

You really need to grow up a little.

Chris

Chris Vine

unread,
Nov 12, 2013, 5:01:36 PM11/12/13
to
On Tue, 12 Nov 2013 14:33:26 +0100
David Brown <da...@westcontrol.removethisbit.com> wrote:
> On 12/11/13 13:37, Alf P. Steinbach wrote:
> > Please don't pay attention to David Brown. Whenever he says
> > something about what others mean, you can be reasonably sure that
> > it's at best misrepresentation, and at worst a complete fantasy. In
> > short, he's heavily into misrepresentation and other forms of
> > trolling.
> >
> > Regarding the C++ expression at hand, -1/2u is well-defined, casting
> > that back to integer will in practice not incur overflow, not even
> > on one complement's machines are sign and magnitude, but the holy
> > standard does admit implementations with rather more perverse value
> > ranges, simply by not considering the possibility that they could
> > exist...
> >
> > One can trust David Brown to latch on to such, and also to not
> > understand whatever he's read about it (he thought -1/2u was UB).
> >
> >
> > Cheers,
> >
> > - Alf (pretty annoyed at himself for being suckered into DB's world)
> >
>
> I don't know if you are reading this, Alf, but could you please just
> drop this attitude? It helps no one, and I am sure I am not the only
> one getting tired of it. /Nothing/ I have posted here has been
> deliberate misrepresentation, lying, or intentional or active
> "trolling".

And this guy is apparently a comp.lang.c++.moderated moderator, or so
he claims.

Chris

Alf P. Steinbach

unread,
Nov 12, 2013, 5:14:38 PM11/12/13
to
On 12.11.2013 22:50, Ian Collins wrote:
>
> I case Alf really has plonked you, he'll see this!

Thanks, but as it turned out that was not necessary: he'd changed his
e-mail address[1] for this. Which was in a way considerate. Which could
almost be baffling, but it makes sense since the main thrust was just
more of the same, trying to engage me and rally others -- appearing
reasonable.


Cheers & thanks!,

- Alf

Notes:
[1] The new mail address [david...@removethis.hesbynett.no] is with a
Norwegian ISP. Mostly only usable for Norwegians. The one already in my
killfile, [da...@westcontrol.removethisbit.com], was with a Norwegian
firm. Since I'm Norwegian I may have encountered "David Brown" or people
that he know, in real life, and possibly I could then have been less
than tactful, which could explain his animosity here.

David Brown

unread,
Nov 12, 2013, 6:20:47 PM11/12/13
to
As I noted in another post (which you may have missed), I happen to have
two different epost addresses when posting from two different computers.
I don't think anyone else has noticed or bothered about it.

I am not Norwegian (I'm Scottish), but I live in Norway.

I have no animosity against you or anyone else. I have disagreed with
you regarding signed overflow behaviour - I make no apology for that,
and I stand by my opinions there. (Of course the factual errors I made
about details of the standards are another matter.) I might have been
"less than tactful" in some of my posts, but I think you'll agree that
that is not uncommon on Usenet, especially when arguments are getting
frustratingly unproductive.



Rosario1903

unread,
Nov 13, 2013, 1:39:03 AM11/13/13
to
On Sat, 09 Nov 2013 16:28:29 +0100, "Alf P. Steinbach" wrote:
>This code is in support of some API functionality:
>[code]
>inline
>auto can_inflate( gdi::Rect const& r, int const dx, int const dy )
> -> bool
>{
> CPPX_XASSERT( INT_MIN/2 < dx && dx < INT_MAX/2 );
> CPPX_XASSERT( INT_MIN/2 < dy && dy < INT_MAX/2 );
>
> typedef unsigned long Unsigned_long;
> auto const msb = ULONG_MAX - (ULONG_MAX >> 1);
> return
> (r.left & msb) == ((Unsigned_long( r.left ) - dx) & msb) &&
> (r.top & msb) == ((Unsigned_long( r.top ) - dy) & msb) &&
....
>
>Can this be written in an even gooder way, for bestest possible code?
>Disclaimer: the code has not been tested or even called.
>Cheers,
>- Alf

it is the compiler that have to do that...
i think the easy form for a C or C++ language would be the follow:

int function(void)
{u32 a, b, r, s, cf;
a=0xFF; b=789799; r=7877;
makeCarryFlagTheLastStatement(&cf);
/* signal to the compiler cf var is the carry flag for overflow
in the last statement and initalize it to 0
*/
s=a*b+c;
if(cf==0) printf("Not carry flag the last statement\n");
else printf("There is one statement with overflow\n");
return 0;
}

where cf would detect integer overflow, unsigned overflow and float
point overflow

David Brown

unread,
Nov 13, 2013, 5:45:26 AM11/13/13
to
As it stands, there are many reasons why code like that could not work.

It is possible on many targets to read the overflow flag from the cpu's
flag register (or "processor status register" - names vary). The
details will be dependent on the cpu in question, and also the compiler
- you would need either inline assembly code or a toolchain-specific
built-in function. However, even if you have made an inline assembly
function that reads the overflow flag, it may not give you the answer
you want.

For some cpu's (such as the PPC), flags are not updated unless the
instruction specifically asks for it - in your "s = a*b + c" a PPC
compiler would use instructions that do not change the flags.

If you write code such as :

s = a * b + c;
if (readOverflowFlag()) ...

where "readOverflowFlag()" is an inline assembly function, the compiler
will typically be free to move the assembly code around with respect to
the "s = a * b + c" calculation. You would have to force the relative
positioning by using volatiles, calls to external code, or other methods
to be sure that the calculation is done as you want, with the order you
want.

And of course you only get the overflow flag from the last operation -
so if you are doing "s = a * b + c" your overflow flag will represent a
check on the addition, but not a check on the multiplication.


One possibility if you need to check the overflow after a number of
calculations is to expand the range of your integers (such as moving to
64-bit integers here), do the calculations, then at the end check for
range overflows before converting back to the 32-bit values.

Rosario1903

unread,
Nov 13, 2013, 10:02:16 AM11/13/13
to
the above would be "s=a*b+r"

>> if(cf==0) printf("Not carry flag the last statement\n");
>> else printf("There is one statement with overflow\n");

for to be clear, in nasm x86 i mean something as:

function:
sub esp, 20
; cf=0, s=4, r=8, b=12, a=16
mov dword[esp+0], 0
mov dword[esp+8], 7877
mov dword[esp+12],789799
mov dword[esp+16],0FFh
; s=a*b+r C statement
mov ecx, 0 ; ecx carry flag
mov edx, 0
mov eax, [esp+16]
mul dword[esp+12]
cmp edx, 0
je .1
mov ecx, 1
.1: add eax, [esp+8]
adc ecx, 0
mov [esp+0], ecx
; if( cf==0 )
cmp dword[esp+0], 0
je etc


>> return 0;
add esp, 20
ret
>> }
>>
>> where cf would detect integer overflow, unsigned overflow and float
>> point overflow
>>
>
>As it stands, there are many reasons why code like that could not work.
>
>It is possible on many targets to read the overflow flag from the cpu's
>flag register (or "processor status register" - names vary).

one could do all with the instruction "adc" = "add and carry" i think
if cpu has not carry flag

>The
>details will be dependent on the cpu in question, and also the compiler
>- you would need either inline assembly code or a toolchain-specific
>built-in function. However, even if you have made an inline assembly
>function that reads the overflow flag, it may not give you the answer
>you want.

yes because each 2 operation "*" and "+" in "s=a*b+c" can write the
carry flag, so it is the compiler that has to do it
or the assembly programer...

>For some cpu's (such as the PPC), flags are not updated unless the
>instruction specifically asks for it - in your "s = a*b + c" a PPC
>compiler would use instructions that do not change the flags.
>
>If you write code such as :
>
> s = a * b + c;
> if (readOverflowFlag()) ...
>
>where "readOverflowFlag()" is an inline assembly function, the compiler
>will typically be free to move the assembly code around with respect to
>the "s = a * b + c" calculation. You would have to force the relative
>positioning by using volatiles, calls to external code, or other methods
>to be sure that the calculation is done as you want, with the order you
>want.

the order i want is the order that the compiler/standard says; there
are no UB there if standard give precedence table for operations and
the use of ()

>And of course you only get the overflow flag from the last operation -
>so if you are doing "s = a * b + c" your overflow flag will represent a
>check on the addition, but not a check on the multiplication.
>
>
>One possibility if you need to check the overflow after a number of
>calculations is to expand the range of your integers (such as moving to
>64-bit integers here), do the calculations, then at the end check for
>range overflows before converting back to the 32-bit values.

i think cpu has instructions for see if there are overflow in each
simple instruction one can find in the statement as in
a=(r*b+(c<<3) - 50.8/12.4) etc etc
and so it would easy count number of overflow for the statement in one
variable
that one define in the same function where that statement is.
this because many threads can have to use the same trick for find
overflow

David Brown

unread,
Nov 13, 2013, 11:58:32 AM11/13/13
to
(Others will hopefully correct me here if I'm wrong...)

The compiler has to generate code /as if/ it followed the ordering in
the source code and the precedence rules for operators. But it can
re-arrange the /actual/ generated code, as long as the effect is the
same. Since any effect on flags is not visible in C or C++ in a
calculation like "a * b + c", the compiler does not have to consider it
when arranging instructions. If the "readOverflowFlag()" is an inline
assembly function, the compiler will probably treat it like a volatile
access - and obey its ordering with respect to other volatile accesses,
to function calls that /may/ have unknown effects, code that /may/ cause
an exception, etc. But simple arithmetic using local data can usually
be moved around quite freely.

I don't think there is any sort of undefined behaviour here - it is just
that C and C++ does not consider effects on flags as "behaviour" of
arithmetic instructions.


I have seen similar things in C, especially in embedded systems, and I
assume the same can apply to C++. People write code like this:

extern volatile bool globalInterruptEnable; // CPU flag
static inline void disableInterrupts(void) {
globalInterruptEnable = false;
}
static inline void enableInterrupts(void) {
globalInterruptEnable = true;
}


static int partA, partB;

void atomicUpdate(int a, b) {
disableInterrupts();
partA = a;
partB = b;
enableInterrupts();
}

I have seen many developers think that code like this will execute the
"partA = a; partB = b;" code with interrupts disabled. The think that
either the volatile nature of the globalInterruptEnable flag, or the
function calls, force this ordering. In fact, the only ordering you are
guaranteed is that that enableInterrupts() comes after
disableInterrupts() - the setting of "parts" can be done before,
between, or after these calls.


It is therefore always dangerous to assume the compiler will generate
code that runs in a particular way or a particular order, just because
it is in that order in your source code.

>
>> And of course you only get the overflow flag from the last operation -
>> so if you are doing "s = a * b + c" your overflow flag will represent a
>> check on the addition, but not a check on the multiplication.
>>
>>
>> One possibility if you need to check the overflow after a number of
>> calculations is to expand the range of your integers (such as moving to
>> 64-bit integers here), do the calculations, then at the end check for
>> range overflows before converting back to the 32-bit values.
>
> i think cpu has instructions for see if there are overflow in each
> simple instruction one can find in the statement as in
> a=(r*b+(c<<3) - 50.8/12.4) etc etc
> and so it would easy count number of overflow for the statement in one
> variable
> that one define in the same function where that statement is.
> this because many threads can have to use the same trick for find
> overflow
>

A compiler certainly /could/ generate such code - but it would make
things bigger and slower. On super-scaler cpus, code like that would
probably cause pipeline stalls and bottlenecks, leading to very much
slower code.

Some processors have "sticky" bits for things like overflows, which are
set by any overflowing operation but are not cleared except by explicit
instructions. These make it easy to do a sequence of operations and see
if there has been an overflow along the way. I think such sticky bits
are more common for floating point operations rather than integer
operations, but obviously it will depend on the cpu in question.

David Harmon

unread,
Nov 14, 2013, 11:53:54 AM11/14/13
to
On Mon, 11 Nov 2013 18:47:23 +0000 in comp.lang.c++, Leigh Johnston
<le...@i42.co.uk> wrote,
>The idiot "plink'd" you which is idiot-speak for blacklisting your
>posts. He has also "plink'd" me as the guy can't handle criticism.

A man's got to know his limitations.
-- Dirty Harry


>

Öö Tiib

unread,
Nov 15, 2013, 1:41:26 AM11/15/13
to
Got to know what he does not want to see and filter that out. Rational.

Gennaro Prota

unread,
Nov 15, 2013, 10:32:34 AM11/15/13
to
On Mon, 11 Nov 2013 19:54:48 +0100, James Kanze <james...@gmail.com>
wrote:
[...]
>> Anyway, there are many good reasons, but for me the most important is a
>> consistent visual layout:
>
>> * function name at fixed place.
>> * return type visually separated.
>
> You mean like the way I've always written function definitions:
>
> bool
> can_inflate( ... )
> {
> }
>
> The function name is always at the start of the line. Has been
> since I learned C. (Back then, about all we had for searching
> was grep, and "grep ^can_inflate" would always get the
> definition, and nothing else.)

Just curious: if starting now, and without that tool-related
limitation, how would you lay out the definition?

--
Genny

---
This email is free from viruses and malware because avast! Antivirus protection is active.
http://www.avast.com

James Kanze

unread,
Nov 15, 2013, 12:45:41 PM11/15/13
to
On Friday, 15 November 2013 15:32:34 UTC, Gennaro Prota wrote:
> On Mon, 11 Nov 2013 19:54:48 +0100, James Kanze <james...@gmail.com>

> wrote:

> [...]
> >> Anyway, there are many good reasons, but for me the most important is a
> >> consistent visual layout:

> >> * function name at fixed place.
> >> * return type visually separated.

> > You mean like the way I've always written function definitions:

> > bool
> > can_inflate( ... )
> > {
> > }

> > The function name is always at the start of the line. Has been
> > since I learned C. (Back then, about all we had for searching
> > was grep, and "grep ^can_inflate" would always get the
> > definition, and nothing else.)

> Just curious: if starting now, and without that tool-related
> limitation, how would you lay out the definition?

Probably the same, but it's impossible to be sure. After all,
I'm not starting now, and who knows what a different background
would have led me to do.

But the tool related limitations are still there. It still use
grep a lot, for example.

Now, if I were designing a language from scratch, so that it
would have maximum readability... I'm pretty sure it wouldn't
look like C++. (But I'm also pretty sure it wouldn't have
anywhere near the acceptance of C++.)

--
James

James Kanze

unread,
Nov 15, 2013, 1:10:16 PM11/15/13
to
On Wednesday, 13 November 2013 16:58:32 UTC, David Brown wrote:
> On 13/11/13 16:02, Rosario1903 wrote:

[...]
> The compiler has to generate code /as if/ it followed the ordering in
> the source code and the precedence rules for operators. But it can
> re-arrange the /actual/ generated code, as long as the effect is the
> same. Since any effect on flags is not visible in C or C++ in a
> calculation like "a * b + c", the compiler does not have to consider it
> when arranging instructions. If the "readOverflowFlag()" is an inline
> assembly function, the compiler will probably treat it like a volatile
> access - and obey its ordering with respect to other volatile accesses,
> to function calls that /may/ have unknown effects, code that /may/ cause
> an exception, etc. But simple arithmetic using local data can usually
> be moved around quite freely.

That's true as far as it goes. Nothing in the condition code is
"observable" in C++. On the other hand:

-- any calculations that would set the overflow flag would
result in undefined behavior in C++, so the compiler can
assume that they won't occur, and

-- the compiler also knows that the condition code is not
observable, and may rearrange code so that the overflow bit
gets set in an intermediate results, as long as it knows
that the final results will be correct. (For example, given
a + b + c, where a is a large positive number, and b and
c fairly large negative values. Executing a + b, and then
the results + c, will not overflow. If the compiler knows
that the hardware rounds results, it may execute
b + c first, then add a, even if b + c results in an
overflow.)

> I don't think there is any sort of undefined behaviour here - it is just
> that C and C++ does not consider effects on flags as "behaviour" of
> arithmetic instructions.

Overflow is undefined behavior. Flags or whatever have nothing
to do with it.

> I have seen similar things in C, especially in embedded systems, and I
> assume the same can apply to C++. People write code like this:

> extern volatile bool globalInterruptEnable; // CPU flag
> static inline void disableInterrupts(void) {
> globalInterruptEnable = false;
> }
> static inline void enableInterrupts(void) {
> globalInterruptEnable = true;
> }

> static int partA, partB;

> void atomicUpdate(int a, b) {
> disableInterrupts();
> partA = a;
> partB = b;
> enableInterrupts();
> }

> I have seen many developers think that code like this will
> execute the "partA = a; partB = b;" code with interrupts
> disabled. The think that either the volatile nature of the
> globalInterruptEnable flag, or the function calls, force this
> ordering. In fact, the only ordering you are guaranteed is
> that that enableInterrupts() comes after disableInterrupts()
> - the setting of "parts" can be done before, between, or after
> these calls.

Developers writing this type of code are targetting a specific
platform, using a specific compiler, which may give additional
guaranteeds with regards to order. What is certain is that the
C++ standard makes no guarantees here, and that with most
general purpose compilers, there is no guarantee that any write
will actually get to globalInterruptEnable. (This is definitely
true with g++ on Sparc. I'm less sure of the guarantees that
Intel gives, but I don't think it is guaranteed with g++ on
Intel either.)

> It is therefore always dangerous to assume the compiler will
> generate code that runs in a particular way or a particular
> order, just because it is in that order in your source code.

That has always been the case.

--
James

Alf P. Steinbach

unread,
Nov 15, 2013, 1:33:31 PM11/15/13
to
On 15.11.2013 19:10, James Kanze wrote:
> On Wednesday, 13 November 2013 16:58:32 UTC, David Brown wrote:
>> On 13/11/13 16:02, Rosario1903 wrote:
>
> [...]
>> The compiler has to generate code /as if/ it followed the ordering in
>> the source code and the precedence rules for operators. But it can
>> re-arrange the /actual/ generated code, as long as the effect is the
>> same. Since any effect on flags is not visible in C or C++ in a
>> calculation like "a * b + c", the compiler does not have to consider it
>> when arranging instructions. If the "readOverflowFlag()" is an inline
>> assembly function, the compiler will probably treat it like a volatile
>> access - and obey its ordering with respect to other volatile accesses,
>> to function calls that /may/ have unknown effects, code that /may/ cause
>> an exception, etc. But simple arithmetic using local data can usually
>> be moved around quite freely.
>
> That's true as far as it goes.

Well no, it's not true as far as it goes.

David Brown is apparently (judging by what you quote) up to his old
tricks of misrepresentation again.

Rosario wrote "it is the compiler that have to do that...", and then
proceeded to sketch a possible language extension.

Then, apparently (I have him killfiled so I do not see the posting), DB
is attacking Rosario by changing the context, treating the proposed
extension as a programmer defined function, essentially with the point
Rosario started with that it's the compiler that has to do that.

IMHO you would do well to do as I, to killfile DB, so that you do not
yet again help him in his efforts of misrepresentation like the above,
and earlier.

David Brown

unread,
Nov 15, 2013, 4:33:55 PM11/15/13
to
The code Rosario posted used unsigned integers (I'm assuming that's what
he meant with "u32"), so if I've interpreted the C++ standards
correctly, "a * b + c" cannot overflow as the operations are defined as
modulo 2^32, and so no undefined behaviour. The cpu's overflow flag may
still be set.

"Overflow" as defined by C++ and "overflow" in a typical cpu flag
register are therefore somewhat orthogonal concepts, I think.

>
>> I have seen similar things in C, especially in embedded systems, and I
>> assume the same can apply to C++. People write code like this:
>
>> extern volatile bool globalInterruptEnable; // CPU flag
>> static inline void disableInterrupts(void) {
>> globalInterruptEnable = false;
>> }
>> static inline void enableInterrupts(void) {
>> globalInterruptEnable = true;
>> }
>
>> static int partA, partB;
>
>> void atomicUpdate(int a, b) {
>> disableInterrupts();
>> partA = a;
>> partB = b;
>> enableInterrupts();
>> }
>
>> I have seen many developers think that code like this will
>> execute the "partA = a; partB = b;" code with interrupts
>> disabled. The think that either the volatile nature of the
>> globalInterruptEnable flag, or the function calls, force this
>> ordering. In fact, the only ordering you are guaranteed is
>> that that enableInterrupts() comes after disableInterrupts()
>> - the setting of "parts" can be done before, between, or after
>> these calls.
>
> Developers writing this type of code are targetting a specific
> platform, using a specific compiler, which may give additional
> guaranteeds with regards to order.

If only that were true! Developer writing this type of code are mostly
doing so because they believe it is correct, having seen lots of
examples in books, websites, and example code from their toolchain
vendor or microcontroller manufacturer.

It is common that compilers /do/ generate code in the order the user
wants, but I have never seen it documented or guaranteed in any way.
(Of course, there are lots of embedded toolchains around - I have used
quite a few, but it's still just a tiny percentage - so I can't
generalise too much.)

For a lot of code, there is no particular reason for the compiler to
generate code in a different order - and compilers generally order the
output based on the source code if there is no good reason to do
something else.

But the fact that it mostly works makes it more surprising to people
when they hit the unusual cases.

> What is certain is that the
> C++ standard makes no guarantees here, and that with most
> general purpose compilers, there is no guarantee that any write
> will actually get to globalInterruptEnable. (This is definitely
> true with g++ on Sparc. I'm less sure of the guarantees that
> Intel gives, but I don't think it is guaranteed with g++ on
> Intel either.)

I think the compiler guarantees that it will send the write instructions
(since "globalInterruptEnable" is volatile). But there is no guarantee
that the /processor/ and/or memory caches and other hardware will pass
the writes on. In more sophisticated cpu's with write buffers could
easily combine the two writes before it finally hits memory. And
certainly they don't guarantee any ordering between writes to
"globalInterruptEnable" and "partA" and "partB".

When using targets with that sort of caching and buffering, you need to
set things up to ensure that writes like "globalInterruptEnable" are
marked appropriately to avoid such problems - clearly such a flag has a
specific address in the memory map rather than being allocated in ram.
And usually you also need to add extra memory synchronisation
instructions - your interrupt control is by function, not just a single
write.

But for smaller and simpler cpus, people write code like that - the
hardware will apply the writes in the order given by the instruction scheme.

>
>> It is therefore always dangerous to assume the compiler will
>> generate code that runs in a particular way or a particular
>> order, just because it is in that order in your source code.
>
> That has always been the case.
>

Yes.

Gennaro Prota

unread,
Nov 15, 2013, 8:17:19 PM11/15/13
to
On Sat, 09 Nov 2013 16:28:29 +0100, Alf P. Steinbach wrote:

> This code is in support of some API functionality:
>
>
> [code]
> inline
> auto can_inflate( gdi::Rect const& r, int const dx, int const dy )

Do you really use int const parameters?

> -> bool
> {
> CPPX_XASSERT( INT_MIN/2 < dx && dx < INT_MAX/2 );
> CPPX_XASSERT( INT_MIN/2 < dy && dy < INT_MAX/2 );

Why? This seems arbitrary.

However... as far as an API goes, I'd see more something that
checks whether a rectangle would grow larger than another one
("bounding box") than a "raw" overflow check. In practice, I'd
expect the user to want to know whether inflating a rect would
make it larger than e.g. 1600x1200, if 1600x1200 is the user's
current display resolution.

PS: Alf, are you experimenting with the charset parameter of
Content-Type? :-)

--
Genny

Alf P. Steinbach

unread,
Nov 15, 2013, 9:27:13 PM11/15/13
to
On 16.11.2013 02:17, Gennaro Prota wrote:
> On Sat, 09 Nov 2013 16:28:29 +0100, Alf P. Steinbach wrote:
>
>> This code is in support of some API functionality:
>>
>>
>> [code]
>> inline
>> auto can_inflate( gdi::Rect const& r, int const dx, int const dy )
>
> Do you really use int const parameters?

Yep.

Same rationale as for anything else const: it reduces the set of things
that might possibly be changing in the code.

And I like the consistency.

I think, if it's worthwhile to make a local automatic variable const,
then it's worthwhile also to make a parameter const.

With respect to function type a top level const on an argument is
however ignored.


>> -> bool
>> {
>> CPPX_XASSERT( INT_MIN/2 < dx && dx < INT_MAX/2 );
>> CPPX_XASSERT( INT_MIN/2 < dy && dy < INT_MAX/2 );
>
> Why? This seems arbitrary.

Inflation subtracts dx from left and adds it to right, so the total
width increase is 2*dx. Hence the particular range values, ensuring that
2*x doesn't overflow. It's just a little sanity check though.

Should that be commented, do you think?


> However... as far as an API goes, I'd see more something that
> checks whether a rectangle would grow larger than another one
> ("bounding box") than a "raw" overflow check. In practice, I'd
> expect the user to want to know whether inflating a rect would
> make it larger than e.g. 1600x1200, if 1600x1200 is the user's
> current display resolution.

Yeah, but that's at a higher level, like r.inflate( dx, dy
).size().contains( Size( 1600, 1200 ) ), or something like that -- I'm
not there yet, since there's so much low level stuff to build.


> PS: Alf, are you experimenting with the charset parameter of
> Content-Type? :-)

Hm, checking...

Content-Type: text/plain; charset=ISO-8859-1; format=flowed

That looks good (it's ISO Latin-1), OK.

But at the start in October I think it was I posted via Google Groups,
and GG does all sorts of unthinkable unmentionable things.


Cheers & thx,

- Alf

Rosario1903

unread,
Nov 16, 2013, 7:30:20 AM11/16/13
to
overflow can happen, even if in one machine, in a set of machine of 2
complement, there would be no UB

>The cpu's overflow flag may
>still be set.
>
>"Overflow" as defined by C++ and "overflow" in a typical cpu flag
>register are therefore somewhat orthogonal concepts, I think.

with "result in overflow" i mean, that result type can not hold the
full result [number] of one math operation

Alf P. Steinbach

unread,
Nov 16, 2013, 8:08:29 AM11/16/13
to
On 13.11.2013 07:39, Rosario1903 wrote:
>
> it is the compiler that have to do that...
> i think the easy form for a C or C++ language would be the follow:
>
> int function(void)
> {u32 a, b, r, s, cf;
> a=0xFF; b=789799; r=7877;
> makeCarryFlagTheLastStatement(&cf);
> /* signal to the compiler cf var is the carry flag for overflow
> in the last statement and initalize it to 0
> */
> s=a*b+c;
> if(cf==0) printf("Not carry flag the last statement\n");
> else printf("There is one statement with overflow\n");
> return 0;
> }
>
> where cf would detect integer overflow, unsigned overflow and float
> point overflow

In very-much-pre-standard Borland's Turbo C++ version 2.01 a
pseudo-variable called _FLAGS was added to the language[1]. Accessing
this variable gave you the i8086 flags register value, presumably like
the value that would be pushed on the stack. Sorry, I don't remember the
details, and documentation is no longer readily available.

A similar but not processor-specific feature /could/ be standardized for
C++, because it would only have possible overhead (such as added
checking or foiled optimizations) where it was used.

So, your suggestion, and the once existing practice of _FLAGS, are two
pretty similar ways to provide overflow checking in an extended
language. A third way, library based, and I think less similar in the
basic idea, is to provide special "checked" types corresponding to the
built-in ones, but with checking. The C# language's `checked` keyword
can be regarded as a way to transparently replace the ordinary built-in
types with such checked types in a designated region of code.

Counting, we now have two main ideas, with a total of four detailed
variations.

Still, I was mainly asking about better ways (for some reasonable
definition of "better") to express the code I quoted. I think 嘱 Tiib's
final suggestion in this thread, of ...

template<typename T>
inline
bool can_enwiden(T const low, T const high, T delta)
{
return delta < 0 ? (std::numeric_limits<T>::min() - delta <= high
&& std::numeric_limits<T>::max() + delta >= low)
: (std::numeric_limits<T>::max() - delta >= high
&& std::numeric_limits<T>::min() + delta <= low);
}

is one such better way, for "better" defined as clarity with not too
much of a performance impact. However, since I didn't understand it up
front, but had to peer at it for a while, I think it needs some
reformulation -- and for the moment I'm keeping the original code.


Cheers, & thanks,

- Alf

Notes:
[1] <url: http://edn.embarcadero.com/article/20841>
[2] <url: news:ebca03bd-dc69-428f...@googlegroups.com>

David Brown

unread,
Nov 16, 2013, 11:01:40 AM11/16/13
to
The standards are quite specific regarding unsigned arithmetic -
arithmetic operations in C and C++ are defined modulo 2^n, and therefore
/cannot/ overflow (and therefore there is no undefined or
implementation-dependent behaviour).

The undefined behaviour is for signed arithmetic. "Undefined behaviour"
is a C/C++ concept here, and follows the standards - the standards say
that signed overflow is UB. It doesn't matter that on most processors,
using what is usually the simplest implementation by the compiler, the
results are often consistent and predictable (as two's complement
operations). It is still undefined behaviour as far as C and C++ is
concerned, and the compiler can generate different code based on that.

Processors usually define arithmetic overflow (unsigned and signed) in
the way you mean here - that the target cannot hold the result as a
simple mathematical operation (without modulo). And of course
/processors/ have perfectly well specified behaviour on overflow - it is
not "undefined behaviour" on that level.


David Brown

unread,
Nov 16, 2013, 11:24:24 AM11/16/13
to
On 16/11/13 14:08, Alf P. Steinbach wrote:
> On 13.11.2013 07:39, Rosario1903 wrote:
>>
>> it is the compiler that have to do that...
>> i think the easy form for a C or C++ language would be the follow:
>>
>> int function(void)
>> {u32 a, b, r, s, cf;
>> a=0xFF; b=789799; r=7877;
>> makeCarryFlagTheLastStatement(&cf);
>> /* signal to the compiler cf var is the carry flag for overflow
>> in the last statement and initalize it to 0
>> */
>> s=a*b+c;
>> if(cf==0) printf("Not carry flag the last statement\n");
>> else printf("There is one statement with overflow\n");
>> return 0;
>> }
>>
>> where cf would detect integer overflow, unsigned overflow and float
>> point overflow
>
> In very-much-pre-standard Borland's Turbo C++ version 2.01 a
> pseudo-variable called _FLAGS was added to the language[1]. Accessing
> this variable gave you the i8086 flags register value, presumably like
> the value that would be pushed on the stack. Sorry, I don't remember the
> details, and documentation is no longer readily available.
>

That is a feature that is also implemented on some embedded compilers,
especially for very small cpus (typically 8-bit devices). And for most
processors, it is possible to write inline assembly functions that
access the flag register(s) directly. But compilers will vary a lot
regarding the guarantees you have for how the other code interacts with
the flag register - there is not much use reading the flags unless you
are sure of how they match with other code.

> A similar but not processor-specific feature /could/ be standardized for
> C++, because it would only have possible overhead (such as added
> checking or foiled optimizations) where it was used.

It /could/ be implemented, and I agree that it would have no overhead
when not used. But I think you would have a hard job specifying exactly
how it would work and interact with other code. In use, it could have
quite significant overhead - it would severely restrict the compiler's
optimiser, and for some processors it would change the type of
instruction used into slower versions (on the PPC, for example, the
compiler will normally generate instructions that do not affect the
flags except if they are strictly needed - such instructions let
superscaler processors do more in parallel).

>
> So, your suggestion, and the once existing practice of _FLAGS, are two
> pretty similar ways to provide overflow checking in an extended
> language. A third way, library based, and I think less similar in the
> basic idea, is to provide special "checked" types corresponding to the
> built-in ones, but with checking. The C# language's `checked` keyword
> can be regarded as a way to transparently replace the ordinary built-in
> types with such checked types in a designated region of code.

I think this would be the way to go - I believe it would be easier to
specify well, easier to implement efficiently in a compiler, and easier
for programmers to use. I think it would also fit better with
processors that have more advanced support for this sort of thing (DSP's
often have things like "sticky" overflow flags that could be useful here).

That also fits with the move in C for support for saturating arithmetic
types, along with fixed point types. "checked" types could be specified
in a similar fashion.

Rosario1903

unread,
Nov 16, 2013, 11:41:38 AM11/16/13
to
On Sat, 16 Nov 2013 17:01:40 +0100, David Brown wrote:

>The standards are quite specific regarding unsigned arithmetic -
>arithmetic operations in C and C++ are defined modulo 2^n, and therefore
>/cannot/ overflow

there is one mathematical overflow, it is not matter how machine
handle that [or standard handle that], yes i would know it handle that
overflwo using result "modulo 2^n"

i'm not much sure of the word "handle" that i mean "tratta"
it seems i lost my dictionary

woodb...@gmail.com

unread,
Nov 16, 2013, 12:48:57 PM11/16/13
to
On Tuesday, November 12, 2013 12:47:28 PM UTC-6, James Kanze wrote:
> On Tuesday, 12 November 2013 13:15:32 UTC, Alf P. Steinbach wrote:

> > Well, two years old. ;-)
>
> For whom? It's been less than a year that I've been able to use
> a limited set of C++11, and most people I know in industry
> cannot use it yet.
>

For lots of people including Google and Facebook
employees. (I'm not really persuaded by Alf in
this case of using auto in function declarations,
but think the number using compilers with 2011
support is both substantial and growing.) The
author of the Boost multi_index library made a
number of C++ 2011 updates

http://lists.boost.org/boost-users/2013/07/79348.php

Those updates were made some time ago so that now
they are available in the latest release of Boost.
I've only heard of one reported problem with the
updates and the author has, I think been able to
address it. Other Boost authors have also done
similar work to this. I'm also among those using
newer compilers.


Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

woodb...@gmail.com

unread,
Nov 16, 2013, 1:20:31 PM11/16/13
to
On Saturday, November 16, 2013 11:48:57 AM UTC-6, woodb...@gmail.com wrote:
> I'm also among those using newer compilers.
>

I've argued similarly before, but C++ 2011 was badly
delayed and should have been 2008 or earlier. Think
of it as C++ 2008 and the adoption rates may make
more sense.

Gennaro Prota

unread,
Nov 16, 2013, 4:44:08 PM11/16/13
to
On Sat, 16 Nov 2013 03:27:13 +0100, Alf P. Steinbach wrote:

[...]
>>> -> bool
>>> {
>>> CPPX_XASSERT( INT_MIN/2 < dx && dx < INT_MAX/2 );
>>> CPPX_XASSERT( INT_MIN/2 < dy && dy < INT_MAX/2 );
>>
>> Why? This seems arbitrary.
>
> Inflation subtracts dx from left and adds it to right, so the total
> width increase is 2*dx. Hence the particular range values, ensuring that
> 2*x doesn't overflow. It's just a little sanity check though.

Ah, OK :-) I hadn't examined the subsequent code, and had
assumed you would add to "one side only" (e.g. only to the right
in the horizontal direction, and only to the bottom in the
vertical direction)

I had a few routines for checking integral operations but not on
this machine, so I'll have to resort to the old school of
"programming in the news reader" :-) The idea was along these
lines, IIRC:

template< typename T >
bool
can_add( T const & a, T const & b )
{
if ( b < 0 ) { // NOTE: T_MIN not handled
return can_subtract( a, -b ) ;
}

T const m( std::numeric_limits< T >::max() ) ;

// the first member can't overflow here, because
// 0 <= b <= m implies 0 <= (m - b) <= m
//
return m - b >= a ;
}

Of course, can_subtract() can be written similarly.

But, as hinted at in the comment, this doesn't handle an
addition with T == int and b == INT_MIN, for instance. I don't
remember how I handled such cases.

[...]
>> PS: Alf, are you experimenting with the charset parameter of
>> Content-Type? :-)
>
> Hm, checking...
>
> Content-Type: text/plain; charset=ISO-8859-1; format=flowed
>
> That looks good (it's ISO Latin-1), OK.
>
> But at the start in October I think it was I posted via Google Groups,
> and GG does all sorts of unthinkable unmentionable things.

Hmm... I see (for your <l66l63$sja$1...@dont-email.me> message)
ISO-8859-15. But I think yesterday I saw a KOI8-R somewhere. I
hope it's not my shiny new newsreader messing up. (But could it?
Isn't the header taken verbatim from the server?)

--
Genny

Paavo Helde

unread,
Nov 16, 2013, 5:11:16 PM11/16/13
to
Rosario1903 <Ros...@invalid.invalid> wrote in
news:gi7f89hotdb91kor2...@4ax.com:

> there is one mathematical overflow,

In mathematics, there is no such thing as integer overflow. One of the
basic properties of the set of integers (Z) is that one can always add or
subtract any two integers and obtain another integer ("Z is closed under
the operations of addition and subtraction").

You need to define your terms a bit more precicely if you want to make a
coherent argument.

Cheers
Paavo

Gennaro Prota

unread,
Nov 17, 2013, 8:49:28 AM11/17/13
to
On Sat, 16 Nov 2013 22:44:08 +0100, Gennaro Prota wrote:

[...]
> I had a few routines for checking integral operations but not on
> this machine, so I'll have to resort to the old school of
> "programming in the news reader" :-) The idea was along these
> lines, IIRC:
>
> template< typename T >
> bool
> can_add( T const & a, T const & b )
> {
> if ( b < 0 ) { // NOTE: T_MIN not handled
> return can_subtract( a, -b ) ;
> }
>
> T const m( std::numeric_limits< T >::max() ) ;
>
> // the first member can't overflow here, because
> // 0 <= b <= m implies 0 <= (m - b) <= m
> //
> return m - b >= a ;
> }
>
> Of course, can_subtract() can be written similarly.
>
> But, as hinted at in the comment, this doesn't handle an
> addition with T == int and b == INT_MIN, for instance. I don't
> remember how I handled such cases.

This is better (NOTE: untested):

template< typename T >
bool
can_add( T const & a, T const & b )
{
if ( b < 0 ) {
T const mn( (std::numeric_limits< T >::min)() );

return ( mn - b ) <= a ;
} else {

T const mx( (std::numeric_limits< T >::max)() );

return a <= ( mx - b ) ;
}
}

I employed some min-max macros protection (the parentheses, and the weird names
"mn" and "mx"). Note that you might want to use the ?: operator.

PS: back to your library, what do you do if dx (or dy) is negative and not
smaller than the rectangle semi-width (or semi-height)? Think e.g. of left=0,
top=0, right=10, bottom=5 and dx=-6, dy=-3.

--
Genny

Alf P. Steinbach

unread,
Nov 17, 2013, 9:20:51 AM11/17/13
to
Well, I don't think any of that is necessary; I can't see any vexing
parse here. But if there was then I'd avoid it simply by using "=" copy
initialization syntax. I like that syntax better anyway. :-)


> Note that you might want to use the ?: operator.
>
> PS: back to your library, what do you do if dx (or dy) is negative and not
> smaller than the rectangle semi-width (or semi-height)? Think e.g. of
> left=0, top=0, right=10, bottom=5 and dx=-6, dy=-3.

The library is just API support, a C++ binding to the API, so to speak.
The API produces an "inverted" rectangle in this case. I.e. it just does
a straightforward update without any checking.

I think it's not unreasonable since the rectangles are used with many
different coordinate systems, and depending on the coordinate system the
"inverted" result can make sense directly.

Someone else asked about the same earlier in the thread.


Cheers,

- Alf

Alf P. Steinbach

unread,
Nov 17, 2013, 9:24:07 AM11/17/13
to
On 17.11.2013 14:49, Gennaro Prota wrote:
>
> I employed some min-max macros protection (the parentheses, and the
> weird names
> "mn" and "mx"). Note that you might want to use the ?: operator.

Oh! You're thinking of MACRO interference. Well I say, those who let
macros called "min" and "max" exist, deserve whatever they get! :D

Cheers,

- Alf


Sam

unread,
Nov 17, 2013, 9:50:22 AM11/17/13
to
For starters, if T is an integer type, passing the arguments by const
reference does not really accomplish anything useful.

Secondly, we all live in the same, real world, where integer arithmetic is
implemented as two's complement. So, unless your implementation platform
throws an exception, or a signal, on integer overflow, all of the above can
simply be reduced to:

template<typename T> bool can_add(T a, T b)
{
return b >= 0 ? (a+b >= a) : (a+b < a);
}

It's quite depressing to learn they don't teach this stuff in school any
more, apparently. If you really want to be fancy, you could throw in a
compile-time check that T is really an integer type, but that's as far as
I'd go.

Alf P. Steinbach

unread,
Nov 17, 2013, 10:24:00 AM11/17/13
to
On 17.11.2013 15:50, Sam wrote:
> Gennaro Prota writes:
>
[snip]
>
> It's quite depressing to learn they don't teach this stuff in school any
> more, apparently. If you really want to be fancy, you could throw in a
> compile-time check that T is really an integer type, but that's as far
> as I'd go.

plink

- Alf

Alf P. Steinbach

unread,
Nov 17, 2013, 11:54:38 AM11/17/13
to
Maybe I should better explain that plink to causal readers.

If Gennaro was clearly a student lacking in basic knowledge, and I also
was such a one, then Sam's comment could be interpreted to actually be
about the school system, and then to some degree excusing the students'
poor understanding of the issue at hand. However, Gennaro is, among
other things, a long time Boost library contributor, I'm a long time
clc++m moderator, and far from indicating novice level participants the
thread so far has been about ordinary professional level stuff. Thus,
Sam's comment is a personal slight that's counter to what he knows,
which strongly indicates pure trolling, a flame bait.

The "plink"[1] then indicates that I've placed him in my news client's
kill file, so that I won't even SEE his further postings in clc++.


- Alf

Notes:
[1] "plink" is (so it was explained to me) the sound of a light-weight
troll hitting the inner surface of the toilet bowl, while "plonk" is the
sound of a more heavy-weight troll being flushed down.

Daniel

unread,
Nov 17, 2013, 12:15:48 PM11/17/13
to
On Sunday, November 17, 2013 11:54:38 AM UTC-5, Alf P. Steinbach wrote:
>
> > plink
>
>
> Maybe I should better explain that plink to causal readers.
>
[Uninteresting self-indulgent explanation snipped]

It seems to this casual reader that Alf is the one playing the troll.

Daniel

Alf P. Steinbach

unread,
Nov 17, 2013, 12:24:38 PM11/17/13
to
On 17.11.2013 18:15, Daniel wrote:
> On Sunday, November 17, 2013 11:54:38 AM UTC-5, Alf P. Steinbach wrote:
>>
>>> plink
>>
>>
>> Maybe I should better explain that plink to causal readers.
>>
> [Uninteresting self-indulgent explanation snipped]

plink

- Alf

Leigh Johnston

unread,
Nov 17, 2013, 12:28:42 PM11/17/13
to
I can explain your "plink" in a single sentence: You are a fucking idiot.

/Leigh

Daniel

unread,
Nov 17, 2013, 1:44:23 PM11/17/13
to
Much better :-) As Tuco might have said in The Good, the Bad and the Ugly, if you're going to plink, plink, don't talk.

Daniel

David Brown

unread,
Nov 17, 2013, 2:45:10 PM11/17/13
to
Unfortunately for you, although real-world processors are almost
invariably two's complement, C and C++ are very specifically /not/ two's
compliment. Signed overflow is explicitly given "undefined behaviour"
in the standards. This means the compiler can generate code that
assumes signed overflow will never occur if that means better code.

In a case like "(a + b >= a)", with /signed/ types for "a" and "b", then
since the compiler /knows/ there can never be an overflow when the code
is run with valid inputs, it can simplify the expression to "b >= 0".

There was a thread about this recently. It was established that some
people /think/ compilers always treat signed integers as two's
compliment, and some people know that the standards say otherwise but
that it would be better if everything was defined as two's compliment
(especially in light of the incorrect assumptions made by the first lot
of people).

But the real-world situation is that in C and C++, signed overflow is
undefined behaviour, and compilers take advantage of that to produce
more optimised object code from real-world source code.

>
> It's quite depressing to learn they don't teach this stuff in school any
> more, apparently. If you really want to be fancy, you could throw in a
> compile-time check that T is really an integer type, but that's as far
> as I'd go.

I have no idea what was taught in schools in the past and in the
present, but I hope that this particular shortcut - elegant though it
might look - is /not/ taught.

Sam

unread,
Nov 17, 2013, 3:30:25 PM11/17/13
to
Another mistake he makes is his strange belief that the public is very
interested in the contents of his personal killfile.

It's really just a symptom of mental masturbation: "I am a very important
person, so if I killfiled you, you must be a loser, NYAH!"


Gennaro Prota

unread,
Nov 17, 2013, 4:00:02 PM11/17/13
to
It isn't an easy problem. One of the main offenders in this case
is <windows.h>. I've never found a reassurance in Microsoft
documentation that their min/max macros are not used in their
own functions. This means that using NOMINMAX in your code and
linking to something else that doesn't use it could potentially
lead to ODR violations.

(I think they do not use them; but that's not a certainty.)

Up until a few weeks ago, I've been avoiding the names "min" and
"max" in my own code, exactly to avoid problems. Then, I wrote a
little class intended to be a model of standard uniform random
number generator; and that *requires* those names.


To protect those names (including if you use
numeric_limits<>::min/max), you have two main alternatives:
either you parenthesize or you use a dummy macro like this:

#define NO_MACRO_EXPANSION
int x = std::numeric_limits< int >::max NO_MACRO_EXPANSION () ;

It prevents expanding any function-like macro named "max" for
the same reason that a ')' does: the macro name isn't followed
by an open parenthesis.

But parentheses also inhibit ADL, whereas the NO_MACRO_EXPANSION
trick doesn't. And, all in all, the macro is probably clearer if
you give it a good name.

--
Genny

Gennaro Prota

unread,
Nov 17, 2013, 4:08:03 PM11/17/13
to
On Sun, 17 Nov 2013 17:54:38 +0100, Alf P. Steinbach wrote:
[...]
>> plink
>
> Maybe I should better explain that plink to causal readers.
>
> If Gennaro was clearly a student lacking in basic knowledge, and I also
> was such a one, then Sam's comment could be interpreted to actually be
> about the school system, and then to some degree excusing the students'
> poor understanding of the issue at hand. However, Gennaro is, among
> other things, a long time Boost library contributor

I have been a contributor. But I attach great importance to
saying that it was an error of youth.

--
Genny

Paavo Helde

unread,
Nov 17, 2013, 4:36:10 PM11/17/13
to
> On Sunday, November 17, 2013 12:24:38 PM UTC-5, Alf P. Steinbach
> wrote:
>> > On Sunday, November 17, 2013 11:54:38 AM UTC-5, Alf P. Steinbach
>> > wrote:
>>
>> >>> plink
>> plink

Alf, doesn't your newsreader support wildcards in "plink"? This way you
could plink the whole group at once and feel much more relaxed!

Cheers
Paavo

alf.p.s...@gmail.com

unread,
Nov 17, 2013, 4:46:01 PM11/17/13
to
plonk
i should have done that long before, but i've been reluctant to do so.
however, this latest sour and misleading comment of yours does not occur as natural part of a discussion you're involved in, it's just you trying to kick someone, anyone, for your own satisfaction of kicking, out of the blue, when you saw a chance. that makes you a pretty bad person as i see it. and considering earlier behavior, in spite of apparent age, you're trolling.


- Alf

Chris Vine

unread,
Nov 17, 2013, 5:22:46 PM11/17/13
to
Who is going to be left for Alf to communicate with, other than those
of his fellow comp.lang.c++.moderated moderators who appear on this
newsgroup (and seem unmoved by his odd behaviour)? However, in that
case he could migrate to that newsgroup and be done with it.

Chris

Sam

unread,
Nov 17, 2013, 5:36:23 PM11/17/13
to
Really? It looks like I might not be the only one, after all, who believes
that Boost is a big pile of crap.

Chris Vine

unread,
Nov 17, 2013, 5:57:27 PM11/17/13
to
I do not know what part of boost Gennaro worked on, but it provides
useful test implementations for the standard. I also still prefer
boost's thread implementation to the standard's. I find the behaviour
of std::thread's destructor bizarre. Ditto std::future (whose
destructor behaves differently when returned by std::async()).

Chris

Tobias Müller

unread,
Nov 18, 2013, 11:43:24 AM11/18/13
to
"Gennaro Prota" <gennaro.pr...@gmail.com> wrote:
> On Sun, 17 Nov 2013 15:24:07 +0100, Alf P. Steinbach wrote:
>> Oh! You're thinking of MACRO interference. Well I say, those who let
>> macros called "min" and "max" exist, deserve whatever they get! :D
>
> It isn't an easy problem. One of the main offenders in this case
> is <windows.h>. I've never found a reassurance in Microsoft
> documentation that their min/max macros are not used in their
> own functions. This means that using NOMINMAX in your code and
> linking to something else that doesn't use it could potentially
> lead to ODR violations.
>
> (I think they do not use them; but that's not a certainty.)

I don't get that. Macros are always expanded, they _never_ generate linker
symbols.

> Up until a few weeks ago, I've been avoiding the names "min" and
> "max" in my own code, exactly to avoid problems. Then, I wrote a
> little class intended to be a model of standard uniform random
> number generator; and that *requires* those names.
>
>
> To protect those names (including if you use
> numeric_limits<>::min/max), you have two main alternatives:
> either you parenthesize or you use a dummy macro like this:
>
> #define NO_MACRO_EXPANSION
> int x = std::numeric_limits< int >::max NO_MACRO_EXPANSION () ;
>
> It prevents expanding any function-like macro named "max" for
> the same reason that a ')' does: the macro name isn't followed
> by an open parenthesis.
>
> But parentheses also inhibit ADL, whereas the NO_MACRO_EXPANSION
> trick doesn't. And, all in all, the macro is probably clearer if
> you give it a good name.

Just
#include <windows.h>
#ifdef max
#undef max
#endif
#ifdef min
#undef min
#endif
and you're done. No reason to clutter your code with yet another macro...

Tobi

Paavo Helde

unread,
Nov 18, 2013, 3:39:40 PM11/18/13
to
=?UTF-8?Q?Tobias=20M=C3=BCller?= <tro...@bluewin.ch> wrote in
news:1509553642406423506.65...@news.eternal-september.
org:
> Just
> #include <windows.h>
> #ifdef max
> #undef max
> #endif
> #ifdef min
> #undef min
> #endif
> and you're done. No reason to clutter your code with yet another
> macro...

This does not work in library headers, which might be included in some
client code which expects to see Windows min/max macros. Been there, burned
myself. Sometimes it is really cumbersome to move the min/max usage into
the .cpp file, and with templates it might be impossible. Fortunately there
are (ugly) workarounds.

Besides, these #ifdef-s above are unneeded, #undef of a name which is not a
macro is a null-op.

Cheers
Paavo


Tobias Müller

unread,
Nov 19, 2013, 1:51:27 AM11/19/13
to
Paavo Helde <myfir...@osa.pri.ee> wrote:
> =?UTF-8?Q?Tobias=20M=C3=BCller?= <tro...@bluewin.ch> wrote in
> news:1509553642406423506.65...@news.eternal-september.
> org:
>> Just
>> #include <windows.h>
>> #ifdef max
>> #undef max
>> #endif
>> #ifdef min
>> #undef min
>> #endif
>> and you're done. No reason to clutter your code with yet another
>> macro...
>
> This does not work in library headers, which might be included in some
> client code which expects to see Windows min/max macros.

True. My public APIs are usually in C (implemented in C++) because of
dynamic loading and interfacing other languages, so I never had that
problem.

Still, you could reimplement min/max in the global namespace if you have to
include windows.h in your header.

> Been there, burned
> myself. Sometimes it is really cumbersome to move the min/max usage into
> the .cpp file, and with templates it might be impossible. Fortunately there
> are (ugly) workarounds.
>
> Besides, these #ifdef-s above are unneeded, #undef of a name which is not a
> macro is a null-op.

Thanks for the hint.

Tobi

James Kanze

unread,
Nov 22, 2013, 6:30:11 PM11/22/13
to
On Friday, 15 November 2013 21:33:55 UTC, David Brown wrote:
> On 15/11/13 19:10, James Kanze wrote:
> > On Wednesday, 13 November 2013 16:58:32 UTC, David Brown wrote:
> >> On 13/11/13 16:02, Rosario1903 wrote:

> > [...]
> >> The compiler has to generate code /as if/ it followed the ordering in
> >> the source code and the precedence rules for operators. But it can
> >> re-arrange the /actual/ generated code, as long as the effect is the
> >> same. Since any effect on flags is not visible in C or C++ in a
> >> calculation like "a * b + c", the compiler does not have to consider it
> >> when arranging instructions. If the "readOverflowFlag()" is an inline
> >> assembly function, the compiler will probably treat it like a volatile
> >> access - and obey its ordering with respect to other volatile accesses,
> >> to function calls that /may/ have unknown effects, code that /may/ cause
> >> an exception, etc. But simple arithmetic using local data can usually
> >> be moved around quite freely.

> > That's true as far as it goes. Nothing in the condition code is
> > "observable" in C++. On the other hand:

> > -- any calculations that would set the overflow flag would
> > result in undefined behavior in C++, so the compiler can
> > assume that they won't occur, and

> > -- the compiler also knows that the condition code is not
> > observable, and may rearrange code so that the overflow bit
> > gets set in an intermediate results, as long as it knows
> > that the final results will be correct. (For example, given
> > a + b + c, where a is a large positive number, and b and
> > c fairly large negative values. Executing a + b, and then
> > the results + c, will not overflow. If the compiler knows
> > that the hardware rounds results, it may execute
> > b + c first, then add a, even if b + c results in an
> > overflow.)

> >> I don't think there is any sort of undefined behaviour here - it is just
> >> that C and C++ does not consider effects on flags as "behaviour" of
> >> arithmetic instructions.

> > Overflow is undefined behavior. Flags or whatever have nothing
> > to do with it.

> The code Rosario posted used unsigned integers (I'm assuming that's what
> he meant with "u32"), so if I've interpreted the C++ standards
> correctly, "a * b + c" cannot overflow as the operations are defined as
> modulo 2^32, and so no undefined behaviour. The cpu's overflow flag may
> still be set.

Even if the unsigned operations don't overflow, the CPU's
overflow flag may be set. Typical CPU's don't distinguish
between signed and unsigned operations; they just add. The
carry flags signals overflow if the operation is treated as
unsigned, the overflow flag if it is treated as signed. It's up
to the assembler programmer (or the compiler) to decide what he
wants to do with these flags, if anything.

> "Overflow" as defined by C++ and "overflow" in a typical cpu flag
> register are therefore somewhat orthogonal concepts, I think.

Not really. They are both based on a more general concept of
overflow. The hardware could call the flags signed overflow and
unsigned overflow if it wanted. The reason it probably doesn't
is that for the most part, the only time a programmer will use
unsigned arithmetic is either for bit manipulations, when
overflow doesn't have any really well defined meaning, or for
multiple precision arithmetic, where the low order elements are
handles as unsigned, and their "overflow" is the carry for the
next higher elements.

> >> I have seen similar things in C, especially in embedded systems, and I
> >> assume the same can apply to C++. People write code like this:

> >> extern volatile bool globalInterruptEnable; // CPU flag
> >> static inline void disableInterrupts(void) {
> >> globalInterruptEnable = false;
> >> }
> >> static inline void enableInterrupts(void) {
> >> globalInterruptEnable = true;
> >> }

> >> static int partA, partB;

> >> void atomicUpdate(int a, b) {
> >> disableInterrupts();
> >> partA = a;
> >> partB = b;
> >> enableInterrupts();
> >> }

> >> I have seen many developers think that code like this will
> >> execute the "partA = a; partB = b;" code with interrupts
> >> disabled. The think that either the volatile nature of the
> >> globalInterruptEnable flag, or the function calls, force this
> >> ordering. In fact, the only ordering you are guaranteed is
> >> that that enableInterrupts() comes after disableInterrupts()
> >> - the setting of "parts" can be done before, between, or after
> >> these calls.

> > Developers writing this type of code are targetting a specific
> > platform, using a specific compiler, which may give additional
> > guaranteeds with regards to order.

> If only that were true! Developer writing this type of code are mostly
> doing so because they believe it is correct, having seen lots of
> examples in books, websites, and example code from their toolchain
> vendor or microcontroller manufacturer.

I'm not saying that there aren't any incompetent programmers
around, but the only people I've seen who write this sort of
thing know very well that it isn't portable. It's quite correct
for the platform they are developing for, and that's what
counts.

> It is common that compilers /do/ generate code in the order the user
> wants,

What does the user want? It's actually very, very rare for a
compiler to generate code in a purely left to right order, as a
naïve programmer might expect (and Java requires). Things like
using Sethi-Ullman numbers to choose which branch of the parse
tree to generate first were wide-spread practice back when I was
writing compilers, twenty-five years ago. Today, instruction
ordering plays an important role, and even the most trivial
peephole optimizer will reorder operations considerably.

> but I have never seen it documented or guaranteed in any way.
> (Of course, there are lots of embedded toolchains around - I have used
> quite a few, but it's still just a tiny percentage - so I can't
> generalise too much.)

> For a lot of code, there is no particular reason for the compiler to
> generate code in a different order - and compilers generally order the
> output based on the source code if there is no good reason to do
> something else.

There are a very large number of reasons why a compiler might
reorder code.

Don't forget, too, that modern processors don't always execute
the machine instructions in the order they occur, and
particularly, they often reorder memory accesses (or suppress
some completely) even when the machine instructions are in the
order you might expect.

> But the fact that it mostly works makes it more surprising to people
> when they hit the unusual cases.

Only if they are incompetent.` (Incompetent to program at this
level, of course. I currently work with some world class
programmers... in numerical analysis; they probably wouldn't be
competent to program at this level.)

> > What is certain is that the
> > C++ standard makes no guarantees here, and that with most
> > general purpose compilers, there is no guarantee that any write
> > will actually get to globalInterruptEnable. (This is definitely
> > true with g++ on Sparc. I'm less sure of the guarantees that
> > Intel gives, but I don't think it is guaranteed with g++ on
> > Intel either.)

> I think the compiler guarantees that it will send the write instructions
> (since "globalInterruptEnable" is volatile). But there is no guarantee
> that the /processor/ and/or memory caches and other hardware will pass
> the writes on. In more sophisticated cpu's with write buffers could
> easily combine the two writes before it finally hits memory. And
> certainly they don't guarantee any ordering between writes to
> "globalInterruptEnable" and "partA" and "partB".

Exactly. For the code you post to work, the compiler would have
to generate barriers or fences for all of the volatile accesses.

That's an aspect that many programmers might not be aware of,
but all programmers should certainly know that volatile only
affects the variable it is attached to, and the the compiler is
free to move accesses to other variabes accross the volatile
access.

> When using targets with that sort of caching and buffering, you need to
> set things up to ensure that writes like "globalInterruptEnable" are
> marked appropriately to avoid such problems - clearly such a flag has a
> specific address in the memory map rather than being allocated in ram.
> And usually you also need to add extra memory synchronisation
> instructions - your interrupt control is by function, not just a single
> write.

> But for smaller and simpler cpus, people write code like that - the
> hardware will apply the writes in the order given by the instruction scheme.

Yes. In the past, it was a lot simpler. The compiler finished
one instruction before starting the next, and all reads and
writes were directly to memory---no caches and no pipelines.

--
James
It is loading more messages.
0 new messages