Good way to write integer overflow checks?

  • Thread starter Alf P. Steinbach
  • Start date
J

James Kanze

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.[/QUOTE] 
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.)[/QUOTE][/QUOTE]
[QUOTE]
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[/QUOTE]
[QUOTE]
template< class T >
decltype( a*b ) mul( T a, T b )
{ return a*b; }[/QUOTE]

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.
[QUOTE]
But you can write, and since you're pragmatic you will eventually write,[/QUOTE]
[QUOTE]
template< class T >
auto mul( T a, T b )
-> decltype( a*b )
{ return a*b; }[/QUOTE]

(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.)
[QUOTE]
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.[/QUOTE]

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.
[QUOTE]
d>> Which means that the human eye finds it much easier to just scan through[/QUOTE]
[QUOTE]
Hm, I can't remember much about Modula-2 declarations.[/QUOTE]

See above.
[QUOTE]
I do remember that good old Niklaus, Praise be Upon Him, for some
inexplicable reason forced the Modula-2 programmer to use UPPERCASE
keywords.[/QUOTE]

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.)
[QUOTE]
Or I think I remember that. Also it was nice with built-in
coroutine support.[/QUOTE]

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.)
 
J

James Kanze

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.

[...]
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.

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

Alf P. Steinbach

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)
 
A

Alf P. Steinbach

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.)[/QUOTE][/QUOTE]
[QUOTE]
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[/QUOTE]
[QUOTE]
template< class T >
decltype( a*b ) mul( T a, T b )
{ return a*b; }[/QUOTE]

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.
[QUOTE]
But you can write, and since you're pragmatic you will eventually write,[/QUOTE]
[QUOTE]
template< class T >
auto mul( T a, T b )
-> decltype( a*b )
{ return a*b; }[/QUOTE]

(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;
}[/QUOTE]

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.

[QUOTE]
.  Otherwise, using decltype is just added verbosity.)[/QUOTE]

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

[QUOTE]
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.[/QUOTE]

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


[QUOTE]
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.[/QUOTE]

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

[QUOTE]
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.[/QUOTE]

Oh it does.

[QUOTE]
For the moment, all of this is new,[/QUOTE]

Well, two years old. ;-)

[QUOTE]
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.[/QUOTE]

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.


[QUOTE]
See above.


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.)


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.)[/QUOTE]

Amen.


Cheers, & hth.,

- Alf
 
A

Alf P. Steinbach

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

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.)[/QUOTE][/QUOTE]
[QUOTE]
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[/QUOTE]
[QUOTE]
template< class T >
decltype( a*b ) mul( T a, T b )
{ return a*b; }[/QUOTE]

And you said something about avoiding complication...  (Of
course, in this case the return is just T, so any decltype is
simply added verbosity.[/QUOTE]

There are no such rule. Consider:

SquareMeters operator*(Meters a, Meters b);

or:

Duration operator-(TimeSpot end, TimeSpot start);
[QUOTE]
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.)[/QUOTE]

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?
[QUOTE]
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.[/QUOTE]

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.
 
J

James Kanze

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 &.)
Times they are a'changing. Yes. :)

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

What? What does it tell you, precisely.
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.
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.
 
I

Ian Collins

Alf said:
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.
 
A

Alf P. Steinbach

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
 
A

Alf P. Steinbach

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.


Cheers & hth.,

- Alf
 
I

Ian Collins

David Brown wrote:

Something Alf should see...
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.


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.

I case Alf really has plonked you, he'll see this!
 
A

Alf P. Steinbach

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 [[email protected]] is with a
Norwegian ISP. Mostly only usable for Norwegians. The one already in my
killfile, [[email protected]], 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.
 
R

Rosario1903

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[/QUOTE]

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
 
R

Rosario1903

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[/QUOTE]

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;[/QUOTE][/QUOTE]

the above would be "s=a*b+r"

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

add esp, 20
ret[QUOTE]
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).[/QUOTE]

one could do all with the instruction "adc" = "add and carry" i think
if cpu has not carry flag
[QUOTE]
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.[/QUOTE]

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...
[QUOTE]
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.[/QUOTE]

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 ()
[QUOTE]
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.[/QUOTE]

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
 
Ö

Öö Tiib

On Mon, 11 Nov 2013 18:47:23 +0000 in comp.lang.c++, Leigh Johnston


A man's got to know his limitations.

Got to know what he does not want to see and filter that out. Rational.
 
G

Gennaro Prota

[...]
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?
 
J

James Kanze

[...]
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++.)
 
J

James Kanze

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.
 
A

Alf P. Steinbach

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.


Cheers & hth.,

- Alf
 
A

Alf P. Steinbach

This code is in support of some API functionality:


Code:
inline
auto can_inflate( gdi::Rect const& r, int const dx, int const dy )[/QUOTE]

Do you really use int const parameters?[/QUOTE]

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.

[QUOTE]
Why? This seems arbitrary.[/QUOTE]

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?

[QUOTE]
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.[/QUOTE]

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.

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

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,099
Messages
2,570,626
Members
47,237
Latest member
David123

Latest Threads

Top