public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* Re: Integral conversions in C/C++
       [not found] <3085.22076015851$1208722372@news.gmane.org>
@ 2008-04-21  3:23 ` Christian Böhme
  2008-04-21  8:28   ` Segher Boessenkool
  0 siblings, 1 reply; 25+ messages in thread
From: Christian Böhme @ 2008-04-21  3:23 UTC (permalink / raw)
  To: gcc-help

Tom St Denis wrote:

> Because there is no such thing as a negative unsigned number.

Actually, the notion of an ``unsigned integer'' as it is known in
the C/C++ world is already an oxymoron.  And it grows from there.
Don't get me started on the float/double nightmare.

> And the promotion applies to the operator

Reiterating a statement without proof does not make said statement
valid.  Show me the section(s) in the standard(s) that limit integral
conversions to assignment statements as you claim.

> The promotions occur (in time) with respect to the order of precedence. 
> If they occur out of order you end up with nastyness (like the float example I
> sent earlier).

At which point in the parsing process of the original example is
there actually an operator precedence resolution involved ?  Care
to elaborate a bit on that ?

>> given the original expression, a = 4294967280UL is a colossal
>> screw-up which I actually expected the compiler to warn me about.
> 
> Why?

The missing warning, the screw-up or both ?

>     You negated an unsigned expression.

Nope.  I multiplied a natural number by -1 expecting to produce
an integer lange enough to hold the value of a natural number
which itself should be large enough to hold the result of a
multiplication of one natural number variable of limited range
and a relatively small natural number constant.  Clean a priori
information that is available to the compiler.  The C/C++
backwardness, however, maimes it into something that probably
was the norm in the 70ies but is unacceptable in the 2000s.
At least in my book.  But then again, it's only PeeCees in the
computing world even on the MPAs nowadays so why bother.

> unsigned char b = 255;
> int a = 4;
> 
> a += b;
>
> Should the result be 3?

Define the ranges of ``unsigned char'' and ``int'' in your example
and I can give you a reasonable answer.

> How is that any different than your example?

Integral _promotion_ vs. integral _conversion_.  Got it ?
If I was to write

int64_t a;
uint32_t b = 0xdeadbeef;

a = -(((int64_t )b) * 10u);

then on a 32 bit machine 10u is promoted to int64_t (which is large
enough to hold the value) and a 64<-64x64 integer multiplication is
performed.  Or isn't it ?  Now, if there was a machine that actually
implemented a 64<-32x32 ``unsigned integer'' multiplication, what
would the result in a of the original example look like if the code
was to be translated according to the standard for this particular
machine ?  Could this multiplication _ever_ be used if the standards
were followed blindly ?

> If we followed your logic, the above statement would read
> 
> 1.  promote b to a signed int (-1)

Wrong on so many levels.  -1 is neither the value after a promotion
nor conversion.  If you indeed understood my logic, then you would
have souped up a conversion example which the above is not.

>>> I have no idea what you're talking about.
>> You will in a couple of years.
> 
> All those having problem understanding the C [and C++] standards raise your hand
> (hint: this is embarrassing, but please raise your hand!!!).

I was probably being too optimistic and should have been more
specific: If you stick to C you never will.  C++ is sloooowly
beginning to move into the right direction.  Too many Cisms and
inconsistencies in it that make coding a tedious task but still
preferable over C and Fortran.  We'll see how far they will have
come within five years from now.

>> That's a completely different problem dealing with _floating point_
>> conversions (C++ 4.8) and irrelevant to the one I was describing.
> 
> Actually, it's the exact same thing.

Right.  Reals, integers, rational and natural numbers.  It's all the
same thing, really.  And because it's all the same thing, really, there
are actually _separate_ clauses for floating point and integer
conversion cases in the C++ standard.  I am with you so far.

>> It appears that you did not read the original post thoroughly as
>> that contained explicit references to the C++ standard.
> 
> C++ and C are similar

Define ``similar''.  And, please, prove it with pointers to the
standards.

> And this has nothing specifically to do with GCC.  Any conforming C or C++
> compiler will generate the same damn output.

Since I have only access to various GCC incarnations nowadays,
it's impossible for me to (dis-)prove that point.  Can you ?

> And just because you're resilient to new information

Once again: There's been no news so far.

 >                                                      doesn't mean
 > your complaints or observations are any more correct then when you
 > first started posting.  If you used the language properly in the
 > first place, you wouldn't be in this mess.

There is no mess as far as my code is concerned as I adhere to the
standards as backward/retarded/perverted the rules may be.  Any well
trained mathematician would, however, think otherwise.  That is the
view I was expressing and the kind of out-of-the-box thinking that
appears to baffle you.  Can't help you with that.


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-21  3:23 ` Integral conversions in C/C++ Christian Böhme
@ 2008-04-21  8:28   ` Segher Boessenkool
  2008-04-21  9:00     ` Christian Böhme
  0 siblings, 1 reply; 25+ messages in thread
From: Segher Boessenkool @ 2008-04-21  8:28 UTC (permalink / raw)
  To: Christian Böhme; +Cc: gcc-help

>>     You negated an unsigned expression.
>
> Nope.  I multiplied a natural number by -1

Maybe that's what you wanted to do, but that's not what you did.

> expecting to produce
> an integer lange enough to hold the value of a natural number
> which itself should be large enough to hold the result of a
> multiplication of one natural number variable of limited range
> and a relatively small natural number constant.  Clean a priori
> information that is available to the compiler.

Hrm, when was the "read the user's mind" patch to GCC applied?
I must have missed it.

> The C/C++
> backwardness, however, maimes it into something that probably
> was the norm in the 70ies but is unacceptable in the 2000s.

If you don't like C, don't use C.

Anyway, this is now all completely off-topic for this list.  Go
find somewhere else to vent, please.


Segher

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-21  8:28   ` Segher Boessenkool
@ 2008-04-21  9:00     ` Christian Böhme
  0 siblings, 0 replies; 25+ messages in thread
From: Christian Böhme @ 2008-04-21  9:00 UTC (permalink / raw)
  To: gcc-help

Segher Boessenkool wrote:

>> Nope.  I multiplied a natural number by -1
> 
> Maybe that's what you wanted to do, but that's not what you did.

Which, again, is another example showing how far off todays computing
world is from actual mathematics.

> Hrm, when was the "read the user's mind" patch to GCC applied?
> I must have missed it.

Very likely.  As some of the other tree transformations that
happened to somehow make it into the code base in the past which
are usually there to make the compiler, erm dare I say, ``smarter''.
Same league, only much simpler to implement.

> If you don't like C, don't use C.

I have been making a living from it for years.  And I do think that
coding might actually make sense in the future.  Given statements
like yours, we're still decades away from that.

> Anyway, this is now all completely off-topic for this list.  Go
> find somewhere else to vent, please.

I am not venting.  I am agitating for sanity/rationality.
And no, this is actually a very GCC centric topic, as there
is a GCC implementation for an architecture which I am working
with as indicated by the multiplier example in my previous post.


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-23 11:22                     ` Andrew Haley
@ 2008-04-24 11:30                       ` John Love-Jensen
  0 siblings, 0 replies; 25+ messages in thread
From: John Love-Jensen @ 2008-04-24 11:30 UTC (permalink / raw)
  To: Christian Böhme; +Cc: GCC-help

Hi Christian,

My apologies, but I do not understand what the point is of your posts.

I must have missed it.  I thought I had it, but given your response to my
post it is evident that I did not understand.

What is your concern?

Sincerely,
--Eljay

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-23  2:30                   ` Christian Böhme
@ 2008-04-23 11:22                     ` Andrew Haley
  2008-04-24 11:30                       ` John Love-Jensen
  0 siblings, 1 reply; 25+ messages in thread
From: Andrew Haley @ 2008-04-23 11:22 UTC (permalink / raw)
  To: Christian Böhme; +Cc: gcc-help

Christian Böhme wrote:
> John Fine wrote:
> 
>> But, if the machine has a 32bit by 32bit multiply that produces the
>> identical 64bit result,  the optimizer is free to use it.
> 
> Here's the catch:
> 
> Optimizers aren't part of the standard.  If the standard(s) were to
> allow for much more explicit expressions, many optimizers would do a
> much better job.  Writing optimizers around standards is what since
> the 90ies characterizes ``good'' compilers.  Here's where the kewl
> stuff happens.
> 
> A strictly standard conforming C/C++ frontend would not (actually
> see the need to) propagate that information to the middle/back ends.

What ridiculous nonsense!  Where in the definition of "strictly standard
conforming" does it forbid the propagation of such information?

Andrew.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-22 22:42                 ` Christian Böhme
@ 2008-04-23 11:11                   ` Andrew Haley
  0 siblings, 0 replies; 25+ messages in thread
From: Andrew Haley @ 2008-04-23 11:11 UTC (permalink / raw)
  To: Christian Böhme; +Cc: gcc-help

Christian Böhme wrote:
> Andrew Haley wrote:
> 
>>> That was the whole point of the OP (Did you read the subject ?).
>>
>> Unfortunately I did. yes.
> 
> Yet you keep going.  Why ?

To try to discover the substance of the complaint, if any.

>> The operands, and the result, are all of type unsigned int, which
>> presumably is 32 bits in this case.
> 
> And given that integral promotions according to [conv.prom] only
> promote as far as to unsigned int as the type with the highest
> conversion rank, where was there intergal promotion applied,
> again ?

It's not: the operands are unsigned int, and stay that way.

>> So what?  The compiler does what the standard says it must.
> 
> Which was the actual incentive for the OP.

I thought you were complaining about the compiler, not the standard.

>> Right: the compiler can use such an instruction, but it must discard
>> the upper part of the result.
> 
> And _here_ is where the standard screws up.

In your opinion.

>> "The correct result"?  The correct result is whatever the standard
>> says it is.
> 
> However counter-intuitive to anyone knowing what linear algebra is it
> may possibly seem.

That's right.

Andrew.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-22 21:05                     ` John Love-Jensen
@ 2008-04-23  8:45                       ` Christian Böhme
  0 siblings, 0 replies; 25+ messages in thread
From: Christian Böhme @ 2008-04-23  8:45 UTC (permalink / raw)
  To: gcc-help

John Love-Jensen wrote:

> As I understand the discussion, the concern was that the negation of a
> uint32_t was undesirably an uint32_t.

That, but in actuality an uint32_t typed result of a 32 bit unsigned
int multiplication although the ISA of the target provides a 64<-32x32
insn that is not emitted due to the frontend hiding this information
from the backend.

> uint16_t * uint16_t ==> int32_t
> 
> Yep, multiplying two uint16_t results in a int32_t, not a uint32_t.
> Surprise!

No surprise here.  Before multiplication, integral promotion makes
int32_ts from the uint16_ts on this particular machine.  Try that on
16 and 64 bit machines and the result types of (s * s) will be
uint16_t and int64_t, respectively.  Since in this example both
uint16_t operands are promoted to the same type no further ``usual
arithmetic conversions'' are applied.  Integral promotion comes
with the catch of promoting only up to int or unsigned int
whatever that on the target may be.

> This forum cannot change the standard.

It can discuss details of its implementation in GCC.

> If anyone wants to change C, or C++, the result is something that
 > may be similar to C or C++, but is not C or C++.

The GNU people have introduced their fair share of mostly private
extensions particularily to C themselves so this ML may actually be
more appropriate than it may initially seem.

> But on the bright side, D Programming Language implements 95%+ of
 > what I would have liked in my own homebrew language, and
> has a GCC implementation (gdc).

Well, I make hardware and write code for a living and the industry
being what it is very much sets the rules within which that happens.

> PS:  I once had a chance to talk to Bjarne Stroustrup, with my litany of
> complaints with C++.  He stopped me short, and replied (paraphrased) "If you
> do not like C++, you are free to create your own language.  I did." 

Quite.  If both of you were given the exact same preconditions,
your language may have been evolved into something similar.  Notice
that C++ has been industry backed from the start while the rest of
the language bunch apparently only has educational character.  The
point being here that a language itself is useless unless an
implementation for a particular hardware exists.  Unless your
application is on a PeeCee, you're out of luck with most of these.


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-22 14:11                 ` John Fine
  2008-04-22 20:48                   ` Andrew Haley
@ 2008-04-23  2:30                   ` Christian Böhme
  2008-04-23 11:22                     ` Andrew Haley
  1 sibling, 1 reply; 25+ messages in thread
From: Christian Böhme @ 2008-04-23  2:30 UTC (permalink / raw)
  To: gcc-help

John Fine wrote:

> But, if the machine has a 32bit by 32bit multiply that produces the 
> identical 64bit result,  the optimizer is free to use it.

Here's the catch:

Optimizers aren't part of the standard.  If the standard(s) were to
allow for much more explicit expressions, many optimizers would do a
much better job.  Writing optimizers around standards is what since
the 90ies characterizes ``good'' compilers.  Here's where the kewl
stuff happens.

A strictly standard conforming C/C++ frontend would not (actually
see the need to) propagate that information to the middle/back ends.
Given a multiplication expression of two 32 bit integers that has
(one of) its arguments cast to a 64 bit type, all that the middle
end receives from the front end is the information that a 64<-64x64
integer multipication is to be performed.  Without _extra_ information
attached to the tree, there is no way other than guessing that the
middle/back ends can infer from that tree that it was actually meant
as 64<-32x32 or indeed 64<-64x64 as modulo 2^64 multiplication.


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-22 13:30               ` Andrew Haley
  2008-04-22 14:11                 ` John Fine
@ 2008-04-22 22:42                 ` Christian Böhme
  2008-04-23 11:11                   ` Andrew Haley
  1 sibling, 1 reply; 25+ messages in thread
From: Christian Böhme @ 2008-04-22 22:42 UTC (permalink / raw)
  To: gcc-help

Andrew Haley wrote:

>> That was the whole point of the OP (Did you read the subject ?).
> 
> Unfortunately I did. yes.

Yet you keep going.  Why ?

> The operands, and the result, are all of type unsigned int, which
> presumably is 32 bits in this case.

And given that integral promotions according to [conv.prom] only
promote as far as to unsigned int as the type with the highest
conversion rank, where was there intergal promotion applied,
again ?

> So what?  The compiler does what the standard says it must.

Which was the actual incentive for the OP.  There are more reasons
to it but those are even more confusing to the general readership of
this ML.  Given that this is gcc-help@gcc.gnu.org and the history of
GCC having, for example, introduced a number of their own _extensions_
(most notably appearing in the Linux kernel code first) that, now
bear with me, actually made it into the C standard because people
actually realized after many years how useful these features were,
it was the rational location to introduce/discuss the topic at hand.
The amount of stirr-up that eventually ensued was interesting from a
psychological aspect but disappointing intellectually.

> Right: the compiler can use such an instruction, but it must discard
> the upper part of the result.

And _here_ is where the standard screws up.  Given that there exists
actually an architecture _implementing_ such an insn, the idea of it
can't be too esoterical, or can it ?  Again, common laws are changed
all the time and so can standards if indeed people understood the
value of and naturally the need for change.  The latter is purely
algebraically motivated while the former usually depends on factors
that only marginally have something to do with rationality as the
type of the responses have clearly shown.

> "The correct result"?  The correct result is whatever the standard
> says it is.

However counter-intuitive to anyone knowing what linear algebra is it
may possibly seem.  That's also olds.

> Right, so it sounds as though you do understand the standard.

I do actually understand a lot more than that.  What gave it away ?
Is it my pointing to the actual standards text and the insinstence on
doing so for the responders to prove their arguments ?

> What, then, is your point?

All in the above.


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-22 20:48                   ` Andrew Haley
@ 2008-04-22 21:05                     ` John Love-Jensen
  2008-04-23  8:45                       ` Christian Böhme
  0 siblings, 1 reply; 25+ messages in thread
From: John Love-Jensen @ 2008-04-22 21:05 UTC (permalink / raw)
  To: GCC-help

Hi everyone,

-->8---

#include <stdint.h>

// ...

int64_t a;
uint32_t b = 8;

a = -(b * 2u);

--->8---

In the context of the question, it is a 32-bit int platform.  The binary and
unary operators on the provided types yield the resulting type.

uint32_t * uint32_t ==> uint32_t
- uint32_t          ==> uint32_t
int64_t = uint32_t  ==> int64_t

As I understand the discussion, the concern was that the negation of a
uint32_t was undesirably an uint32_t.  Which is what the standard says it
must do on this kind of platform.

It appears that the desired behavior is...
a = -(int64_t)(b * 2u);
...but without having to explicitly specify the conversion.  Alas,
explicitly specifying the conversion is needed.

Here's a bit of code that I <sarcasm>love</sarcasm>:

--------------------------------------------------
#include <iostream>
#include <typeinfo>
// Assuming a 32-bit int platform, and short is 16-bit.
typedef unsigned short int uint16_t;
typedef signed int int32_t;
int main()
{
  uint16_t s = 0xFFFFU;
  std::cout << (s * s) << std::endl;
  std::cout << typeid(uint16_t).name() << std::endl;
  std::cout << typeid(int32_t).name() << std::endl;
  std::cout << typeid(s).name() << std::endl;
  std::cout << typeid(s * s).name() << std::endl;
}
--------------------------------------------------

uint16_t * uint16_t ==> int32_t

Yep, multiplying two uint16_t results in a int32_t, not a uint32_t.
Surprise!

There are a few sharp edges to C and C++.

This forum can help diagnose when someone hits one of those sharp edges.

This forum cannot change the standard.  This is not a standards forum.

If anyone wants to change C, or C++, the result is something that may be
similar to C or C++, but is not C or C++.

Anyone can use FSF's GCC to create their own language.

I've tried, and it turns out that writing my own perfect language is quite a
bit more work than I thought going into the project.  Now my Aho dragon book
is just collecting dust.  But on the bright side, D Programming Language
implements 95%+ of what I would have liked in my own homebrew language, and
has a GCC implementation (gdc).

Sincerely,
--Eljay

PS:  I once had a chance to talk to Bjarne Stroustrup, with my litany of
complaints with C++.  He stopped me short, and replied (paraphrased) "If you
do not like C++, you are free to create your own language.  I did."  In
hindsight, I'm sure he's heard more than his fair share of complaints about
C++ (my apologies Bjarne!), I appreciate his response, and I'm grateful he
stopped me before I continued to embarrass myself.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-22 14:11                 ` John Fine
@ 2008-04-22 20:48                   ` Andrew Haley
  2008-04-22 21:05                     ` John Love-Jensen
  2008-04-23  2:30                   ` Christian Böhme
  1 sibling, 1 reply; 25+ messages in thread
From: Andrew Haley @ 2008-04-22 20:48 UTC (permalink / raw)
  To: John Fine; +Cc: Christian Böhme, gcc-help

John Fine wrote:
> Andrew Haley wrote:
> 
>> Christian Böhme wrote:
>>  
>>
>>> If, as already assumed elsewhere, the 32 bit machine in question
>>> provided a 32 unsigned integer multiplication that produces a 64
>>> bit unsigned integer result, the compiler will _never_ emit code
>>> using this instruction based on information withheld by a standard
>>> conforming frontend that the type of the result _must_ be that
>>> of the operands and precluding the conversion to a type large
>>> enough such that the multiplication is closed.
>>>   
>>
>> Right: the compiler can use such an instruction, but it must discard
>> the upper part of the result.
>
> I don't know if any optimizer does pay attention to this case, but the
> standard can't prevent an optimizer from doing so.
> 
> If you cast a 32bit value (int or unsigned int) to 64bit then
> immediately multiply it by another 32bit value,

That's not what the example did.

> the standard meaning is
> to do a 64bit by 64bit multiply and keep only the low 64 bits of the
> 128bit result.

Right.

> But, if the machine has a 32bit by 32bit multiply that produces the
> identical 64bit result, the optimizer is free to use it.

Of course, by the usual "as if" rule.  

> The standard
> may forget that each input to the multiply only has 32 significant
> bits.  But the optimizer can remember that.  So it has two nominally
> 64bit values to multiply, which each only have 32 significant bits.  So
> it can know that the full 64bit result of a 32bit multiply would match
> the low 64bit result of a 64bit multiply.
> 
> So I hope the "_never_" stated above is actually incorrect.

It was correct, for the example as stated:

-->8---

#include <stdint.h>

// ...

int64_t a;
uint32_t b = 8;

a = -(b * 2u);

--->8---

Andrew.


^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-22 13:30               ` Andrew Haley
@ 2008-04-22 14:11                 ` John Fine
  2008-04-22 20:48                   ` Andrew Haley
  2008-04-23  2:30                   ` Christian Böhme
  2008-04-22 22:42                 ` Christian Böhme
  1 sibling, 2 replies; 25+ messages in thread
From: John Fine @ 2008-04-22 14:11 UTC (permalink / raw)
  To: Andrew Haley; +Cc: Christian Böhme, gcc-help

Andrew Haley wrote:

>Christian Böhme wrote:
>  
>
>>If, as already assumed elsewhere, the 32 bit machine in question
>>provided a 32 unsigned integer multiplication that produces a 64
>>bit unsigned integer result, the compiler will _never_ emit code
>>using this instruction based on information withheld by a standard
>>conforming frontend that the type of the result _must_ be that
>>of the operands and precluding the conversion to a type large
>>enough such that the multiplication is closed.
>>    
>>
>
>Right: the compiler can use such an instruction, but it must discard
>the upper part of the result.
>
>  
>
I don't know if any optimizer does pay attention to this case, but the 
standard can't prevent an optimizer from doing so.

If you cast a 32bit value (int or unsigned int) to 64bit then 
immediately multiply it by another 32bit value, the standard meaning is 
to do a 64bit by 64bit multiply and keep only the low 64 bits of the 
128bit result.

But, if the machine has a 32bit by 32bit multiply that produces the 
identical 64bit result, the optimizer is free to use it.  The standard 
may forget that each input to the multiply only has 32 significant 
bits.  But the optimizer can remember that.  So it has two nominally 
64bit values to multiply, which each only have 32 significant bits.  So 
it can know that the full 64bit result of a 32bit multiply would match 
the low 64bit result of a 64bit multiply.

So I hope the "_never_" stated above is actually incorrect.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-22 12:33             ` Christian Böhme
@ 2008-04-22 13:30               ` Andrew Haley
  2008-04-22 14:11                 ` John Fine
  2008-04-22 22:42                 ` Christian Böhme
  0 siblings, 2 replies; 25+ messages in thread
From: Andrew Haley @ 2008-04-22 13:30 UTC (permalink / raw)
  To: Christian Böhme; +Cc: gcc-help

Christian Böhme wrote:
> Andrew Haley wrote:
> 
>> ISO/IEC 14882:1998(E)
>> 5 Expressions
>>
>> 9
> 
> That's _chapter_ 5 [expr], para 9 over here.
> 
>>> vs. 4.7 "Integral conversions" as in the subject of the OP.
>>
>> Right, and you have now had the exact language quoted to you.
> 
> Which, surprise, makes no mention of integral conversions nor
> references to section 4.7 [conv.integral].  There, para 7 deserves
> special attention:
> 
> "The conversions allowed as integral promotions are excluded from
>  the set of integral conversions."
> 
> That was the whole point of the OP (Did you read the subject ?).

Unfortunately I did. yes.

> But back to the original example:
> 
>> Your first example was
>>
>> int64_t a;
>> uint32_t b = 8;
>>
>> a = -(b * 2u);
>>
>> So, the last section of Para 9 applies: b is promoted to unsigned
>> int,
> 
> According to the OP b is of type uint32_t which coincidentally in
> this particular example on a 32 bit machine, is a typedef from
> unsigned int.

OK.

> Contrary to what the specifier may suggest, we all
> know that ``typedef'' actually only introduces another name or
> _alias_ for the name of the type that is given in a typedef
> declaration.  The literal constant 2u is, again, of type unsigned
> int.  According to 5.6 [expr.mul], (b * 2u) then yields a result
> that is of type unsigned int.  Where was there integral promotion
> applied again ?

The operands, and the result, are all of type unsigned int, which
presumably is 32 bits in this case.

>> int64_t a;
>> uint32_t b = 8;
>>
>> a = -((int64_t )(b * 2u));
>>
>> the unsigned int result of (b * 2u) is converted to int64_t and
>> that is negated.
> 
> As already stated elsewhere, this only _happens_ to be the correct
> result.  If b = 0xffffffff, then the above version yields the
> negated value of (b * 2u), the latter being not closed over
> the set that uint32_t represents producing a modulo 2^32 result.

So what?  The compiler does what the standard says it must.

> If, as already assumed elsewhere, the 32 bit machine in question
> provided a 32 unsigned integer multiplication that produces a 64
> bit unsigned integer result, the compiler will _never_ emit code
> using this instruction based on information withheld by a standard
> conforming frontend that the type of the result _must_ be that
> of the operands and precluding the conversion to a type large
> enough such that the multiplication is closed.

Right: the compiler can use such an instruction, but it must discard
the upper part of the result.

> A 64 bit unsigned
> int can then be negated yielding a _negative_ number as the correct
> result. 

"The correct result"?  The correct result is whatever the standard
says it is.

> The latter can be enforced by a statement like
>
> a = -(((uint64_t )b) * 2u);
> 
> which, however, requests a 64 bit unsigned integer multiplication
> which may be non existent or abysmally slow on the target.  This
> is the problem that _can_ precisely be avoided by integral conversion
> applied during the multiplication operation.

Right, so it sounds as though you do understand the standard.  What,
then, is your point?

Andrew.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-21 23:51           ` Andrew Haley
@ 2008-04-22 12:33             ` Christian Böhme
  2008-04-22 13:30               ` Andrew Haley
  0 siblings, 1 reply; 25+ messages in thread
From: Christian Böhme @ 2008-04-22 12:33 UTC (permalink / raw)
  To: gcc-help

Andrew Haley wrote:

> ISO/IEC 14882:1998(E)
> 5 Expressions
> 
> 9

That's _chapter_ 5 [expr], para 9 over here.

>> vs. 4.7 "Integral conversions" as in the subject of the OP.
> 
> Right, and you have now had the exact language quoted to you.

Which, surprise, makes no mention of integral conversions nor
references to section 4.7 [conv.integral].  There, para 7 deserves
special attention:

"The conversions allowed as integral promotions are excluded from
  the set of integral conversions."

That was the whole point of the OP (Did you read the subject ?).
But back to the original example:

> Your first example was
> 
> int64_t a;
> uint32_t b = 8;
> 
> a = -(b * 2u);
> 
> So, the last section of Para 9 applies: b is promoted to unsigned
> int,

According to the OP b is of type uint32_t which coincidentally in
this particular example on a 32 bit machine, is a typedef from
unsigned int.  Contrary to what the specifier may suggest, we all
know that ``typedef'' actually only introduces another name or
_alias_ for the name of the type that is given in a typedef
declaration.  The literal constant 2u is, again, of type unsigned
int.  According to 5.6 [expr.mul], (b * 2u) then yields a result
that is of type unsigned int.  Where was there integral promotion
applied again ?

> int64_t a;
> uint32_t b = 8;
> 
> a = -((int64_t )(b * 2u));
> 
> the unsigned int result of (b * 2u) is converted to int64_t and
> that is negated.

As already stated elsewhere, this only _happens_ to be the correct
result.  If b = 0xffffffff, then the above version yields the
negated value of (b * 2u), the latter being not closed over
the set that uint32_t represents producing a modulo 2^32 result.

If, as already assumed elsewhere, the 32 bit machine in question
provided a 32 unsigned integer multiplication that produces a 64
bit unsigned integer result, the compiler will _never_ emit code
using this instruction based on information withheld by a standard
conforming frontend that the type of the result _must_ be that
of the operands and precluding the conversion to a type large
enough such that the multiplication is closed.  A 64 bit unsigned
int can then be negated yielding a _negative_ number as the correct
result.  The latter can be enforced by a statement like

a = -(((uint64_t )b) * 2u);

which, however, requests a 64 bit unsigned integer multiplication
which may be non existent or abysmally slow on the target.  This
is the problem that _can_ precisely be avoided by integral conversion
applied during the multiplication operation.


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-21 14:18         ` Christian Böhme
  2008-04-21 15:55           ` Tom St Denis
@ 2008-04-21 23:51           ` Andrew Haley
  2008-04-22 12:33             ` Christian Böhme
  1 sibling, 1 reply; 25+ messages in thread
From: Andrew Haley @ 2008-04-21 23:51 UTC (permalink / raw)
  To: Christian Böhme; +Cc: gcc-help

Christian Böhme wrote:
> Andrew Haley wrote:
> 
>> Section 5 Para. 9
> 
> That's talking about _relational_ operators and starts with
> 
> "The usual arithmetic conversions are performed on operands of
>  arithmetic or enumeration type."

No, it isn't.  

ISO/IEC 14882:1998(E)
5 Expressions

9

Many binary operators that expect operands of arithmetic or
enumeration type cause conversions and yield result types in a similar
way. The purpose is to yield a common type, which is also the type of
the result. This pattern is called the usual arithmetic conversions,
which are defined as follows:

- If either operand is of type long double, the other shall be
  converted to long double.

- Otherwise, if either operand is double, the other shall be converted
  to double.

- Otherwise, if either operand is float, the other shall be converted to float. 

- Otherwise, the integral promotions (4.5) shall be performed on both
  operands.54)

- Then, if either operand is unsigned long the other shall be
  converted to unsigned long.

- Otherwise, if one operand is a long int and the other unsigned int,
  then if a long int can represent all the values of an unsigned int,
  the unsigned int shall be converted to a long int; otherwise both
  operands shall be converted to unsigned long int.

- Otherwise, if either operand is long, the other shall be converted
  to long.

- Otherwise, if either operand is unsigned, the other shall be
  converted to unsigned. [Note: otherwise, the only remaining case is
  that both operands are int ]

> going on about pointer conversions ectpp.  My example did,
> however, neither.  Any more pointers ?
> 
>> and Section 4.5.
> 
> That's "Integral promotions"

Well, yes.  That's what applies here.  The integral promotions
are relevant, because they are *directly* referred to in the
paragraph above.

> vs. 4.7 "Integral conversions" as in the subject of the OP.

Right, and you have now had the exact language quoted to you.

Your first example was

int64_t a;
uint32_t b = 8;

a = -(b * 2u);

So, the last section of Para 9 applies: b is promoted to unsigned
int, and the result, and unsigned int, is negated, yielding
another unsigned int.

In this case:

int64_t a;
uint32_t b = 8;

a = -((int64_t )(b * 2u));

the unsigned int result of (b * 2u) is converted to int64_t and
that is negated.

Andrew.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-21 14:18         ` Christian Böhme
@ 2008-04-21 15:55           ` Tom St Denis
  2008-04-21 23:51           ` Andrew Haley
  1 sibling, 0 replies; 25+ messages in thread
From: Tom St Denis @ 2008-04-21 15:55 UTC (permalink / raw)
  To: Christian Böhme; +Cc: gcc-help

Christian Böhme wrote:
> Andrew Haley wrote:
>
>> Section 5 Para. 9
>
> That's talking about _relational_ operators and starts with
>
> "The usual arithmetic conversions are performed on operands of
>  arithmetic or enumeration type."
>
> going on about pointer conversions ectpp.  My example did,
> however, neither.  Any more pointers ?

Read section 2.7 (pp. 45) of the C programming language book (K&R's book).

While not the "standard," it discusses the same rules.

Tom



^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-21 11:48       ` Andrew Haley
@ 2008-04-21 14:18         ` Christian Böhme
  2008-04-21 15:55           ` Tom St Denis
  2008-04-21 23:51           ` Andrew Haley
  0 siblings, 2 replies; 25+ messages in thread
From: Christian Böhme @ 2008-04-21 14:18 UTC (permalink / raw)
  To: gcc-help

Andrew Haley wrote:

> Section 5 Para. 9

That's talking about _relational_ operators and starts with

"The usual arithmetic conversions are performed on operands of
  arithmetic or enumeration type."

going on about pointer conversions ectpp.  My example did,
however, neither.  Any more pointers ?

> and Section 4.5.

That's "Integral promotions" vs. 4.7 "Integral conversions" as
in the subject of the OP.


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-20 23:07     ` Christian Böhme
@ 2008-04-21 11:48       ` Andrew Haley
  2008-04-21 14:18         ` Christian Böhme
  0 siblings, 1 reply; 25+ messages in thread
From: Andrew Haley @ 2008-04-21 11:48 UTC (permalink / raw)
  To: Christian Böhme; +Cc: gcc-help

Christian Böhme wrote:
> Andrew Haley wrote:
> 
>>>> What type is the expression -(b * 2u)?
> 
>> The correct answer is unsigned int.
> 
> Here's the question: Why ?  And by which logic ?

Because the standard says so.

>> Please read C99 Section 6.3.1.1 Para 2, and Section 6.3.1.8.
> 
> Care to point to the appropriate sections in the C++ standard ?

Section 5 Para. 9 and Section 4.5.  The language is copied
from the C Standard.

Andrew.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
       [not found] <23793.5913996354$1208708537@news.gmane.org>
@ 2008-04-21  0:36 ` Christian Böhme
  0 siblings, 0 replies; 25+ messages in thread
From: Christian Böhme @ 2008-04-21  0:36 UTC (permalink / raw)
  To: gcc-help

Tom St Denis wrote:

> But it isn't.

That's no news.  I am interested in _why_ it is not.  I have yet to
see a plausible explanation for the original algebraic statement why
a does not contain a _negative_ value although a's type allows it and
the compiler is given enough freedom to allocate a temporary large
enough and actually technically available (which is both the case)
to hold such a result.

> Numerically, that's what it does.

This is what is done _technically_.  In pure algebraic terms and
given the original expression, a = 4294967280UL is a colossal
screw-up which I actually expected the compiler to warn me about.

> you took 8, doubled it, then negated it as a 32-bit two's complement.

Actually, that's what the compiler did and _not_ what the expression
suggested.

> I ask again.  Why would that be sign extended?

You are missing the point.  The result of b * 2u is to be multiplied
by -1 and stored in a.  How such a simple algebraic statement can
possibly be interpreted as some sick type conversion operation was
the point of the original post.  Bottom line: If I wanted to use
modulo arithmetic I'd be _explicit_ about it.

> You're right that a conversion is applied before being stored, but the conversion
> rule applies to the = operator, nothing else.

Interesting.  Can you point me to the section(s) in the standard(s)
where temporary expressions are explicitly left out from integral
conversions ?

> And the rule states that from a 32-bit unsigned value that it will
 > be zero extended.  Otherwise, the above statement ends with -16 in
 > a which is not what you're doing.

Ironically, that is what I was saying _algebraically_.  And I was
exclusively interested in the rationale behind the technical result.

> I have no idea what you're talking about.

You will in a couple of years.

> b = 0xFFFFFFFF * 2

b = 0xffffffff * 2 isn't the same as b = 0xffffffff * 2u.
2 is an integer constant while 2u is a constant for a natural number.

> Using your logic ...
> 
> float a = 3;
> int b;
> 
> b = a / 1.5;

That's a completely different problem dealing with _floating point_
conversions (C++ 4.8) and irrelevant to the one I was describing.

> I suggest you read either the C standard or at least the K&R C book
 > and learn about conversion rules, variable promotions, etc...

It appears that you did not read the original post thoroughly as
that contained explicit references to the C++ standard.

> This is also totally off-topic for this list, as you're not
 > discussing a GCC bug.

This is gcc-help and not gcc-bugs.


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-20 18:16   ` Andrew Haley
@ 2008-04-20 23:07     ` Christian Böhme
  2008-04-21 11:48       ` Andrew Haley
  0 siblings, 1 reply; 25+ messages in thread
From: Christian Böhme @ 2008-04-20 23:07 UTC (permalink / raw)
  To: gcc-help

Andrew Haley wrote:

>>> What type is the expression -(b * 2u)?

> The correct answer is unsigned int.

Here's the question: Why ?  And by which logic ?

> Please read C99 Section 6.3.1.1 Para 2, and Section 6.3.1.8.

Care to point to the appropriate sections in the C++ standard ?


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
  2008-04-20 17:57 ` Christian Böhme
@ 2008-04-20 18:16   ` Andrew Haley
  2008-04-20 23:07     ` Christian Böhme
  0 siblings, 1 reply; 25+ messages in thread
From: Andrew Haley @ 2008-04-20 18:16 UTC (permalink / raw)
  To: Christian Böhme; +Cc: gcc-help

Christian Böhme wrote:
> Tom St Denis wrote:
> 
>> What type is the expression -(b * 2u)?
> 
> It _should_ be that of the destination type of the whole expression.
> and thus integral conversion of an rvalue applied.

The correct answer is unsigned int.

Please read C99 Section 6.3.1.1 Para 2, and Section 6.3.1.8.

Andrew.

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
       [not found] <10044.4877906286$1208659138@news.gmane.org>
@ 2008-04-20 17:57 ` Christian Böhme
  2008-04-20 18:16   ` Andrew Haley
  0 siblings, 1 reply; 25+ messages in thread
From: Christian Böhme @ 2008-04-20 17:57 UTC (permalink / raw)
  To: gcc-help

Tom St Denis wrote:

> What type is the expression -(b * 2u)?

It _should_ be that of the destination type of the whole expression.
and thus integral conversion of an rvalue applied.

> And why would the number 2^32 - 16 be sign extended when stored in
 > a 64-bit signed int?

2^32 - 16 is not what -(b * 2u) expresses.  The result of x = b * 2u
can _not_ possibly be stored in a 32 bit object.  Consequently, the
type of its result x should be a type that can contain all possible
values of (b * 2u) (which uint32_t clearly can not) _and_ be an
rvalue for -(·) whose destination type again is large enough to
hold the value of (b * 2u).

>    long long a;
>    unsigned long b;
> 
>    b = 8;
>    a = (int)(-(b * 2U));

> Why does this work when your example does not?

For once, it does not give exact sizes for the objects in use.
Secondly, the type cast is acually redundant to the original version.
Finally, the example may work for b = 8 but not for b = 0xffffffff
and hence is _wrong_ with b being a _variable_ whose value no
compiler can ever predict an therefore _should_ use a temporary
with an appropriate type which, again, is the point of the
whole discussion.


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Integral conversions in C/C++
@ 2008-04-20  6:11 Christian Böhme
  0 siblings, 0 replies; 25+ messages in thread
From: Christian Böhme @ 2008-04-20  6:11 UTC (permalink / raw)
  To: gcc-help

Hi all,

I ran into a problem with an expression that I imagined is too
trivial to even needing a second thought in the first place.
However, on a 32 bit machine, the code

--->8---

#include <stdint.h>

// ...

int64_t a;
uint32_t b = 8;

a = -(b * 2u);

--->8---

assigns a the value 0xfffffff0 while no warnings were issued even
when compiling with all warnings (-Wall) switched on.  Strangely
enough and for reasons escaping me

--->8---

#include <stdint.h>

// ...

int64_t a;
uint32_t b = 8;

a = -((int64_t )(b * 2u));

--->8---

produces the expected value of 0xfffffffffffffff0 (or -16).

The destination type (ie, a's type) is the same in both versions
which is large enough to hold the result of the RHS of a = -(x)
with x being a temporary variable for the result of the sub
expression (b * 2u).  In order to represent the latter's result,
its destination type clearly cannot be that of its operands and
must be converted to a larger type.  Since a's type satisfies
these requirements already, it seems logical to assume that x
is defined with this type also which clearly is not the case
with the first version.  Having 4.7 of the ISO C++ standard
in mind which deals with integral _conversions_ (as opposed
to integral _promotions_) at which point may I be missing
something here ?  Where's the logic in having to insert a
type cast for a temporary when it can be unambiguously inferred
from the destination type of the expression ?  Is this an
``implementation detail'' ?


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Re: Integral conversions in C/C++
@ 2008-04-20  4:58 Tom St Denis
  0 siblings, 0 replies; 25+ messages in thread
From: Tom St Denis @ 2008-04-20  4:58 UTC (permalink / raw)
  To: gcc-help



On Sat 19/04/08  9:57 PM , Christian Böhme monodhs@gmx.de sent:
> Hi all,
> 
> 
> 
> I ran into a problem with an expression that I imagined is too
> 
> trivial to even needing a second thought in the first place.
> 
> However, on a 32 bit machine, the code
> 
> 
> 
> --->8---
> 
> 
> 
> #include 
> 
> 
> 
> // ...
> 
> 
> 
> int64_t a;
> 
> uint32_t b = 8;
> 
> 
> 
> a = -(b * 2u);
> 
> 
> 
> --->8---
> 
> 
> 
> assigns a the value 0xfffffff0 while no warnings were issued even
> 
> when compiling with all warnings (-Wall) switched on.  Strangely
> 
> enough and for reasons escaping me

What type is the expression -(b * 2u)?  And why would the number 2^32 - 16 be
sign extended when stored in a 64-bit signed int?  2^32 - 16 is a valid positive
number for the 64-bit type.

Consider

int main(void)
{
   long long a;
   unsigned long b;

   b = 8;
   a = (int)(-(b * 2U));
   printf("a == %lld\n", a);
   return 0;
}

Why does this work when your example does not?

Tom

^ permalink raw reply	[flat|nested] 25+ messages in thread

* Integral conversions in C/C++
@ 2008-04-20  4:49 Christian Böhme
  0 siblings, 0 replies; 25+ messages in thread
From: Christian Böhme @ 2008-04-20  4:49 UTC (permalink / raw)
  To: gcc-help

Hi all,

I ran into a problem with an expression that I imagined is too
trivial to even needing a second thought in the first place.
However, on a 32 bit machine, the code

--->8---

#include <stdint.h>

// ...

int64_t a;
uint32_t b = 8;

a = -(b * 2u);

--->8---

assigns a the value 0xfffffff0 while no warnings were issued even
when compiling with all warnings (-Wall) switched on.  Strangely
enough and for reasons escaping me

--->8---

#include <stdint.h>

// ...

int64_t a;
uint32_t b = 8;

a = -((int64_t )(b * 2u));

--->8---

produces the expected value of 0xfffffffffffffff0 (or -16).

The destination type (ie, a's type) is the same in both versions
which is large enough to hold the result of the RHS of a = -(x)
with x being a temporary variable for the result of the sub
expression (b * 2u).  In order to represent the latter's result,
its destination type clearly cannot be that of its operands and
must be converted to a larger type.  Since a's type satisfies
these requirements already, it seems logical to assume that x
is defined with this type also which clearly is not the case
with the first version.  Having 4.7 of the ISO C++ standard
in mind which deals with integral _conversions_ (as opposed
to integral _promotions_) at which point may I be missing
something here ?  Where's the logic in having to insert a
type cast for a temporary when it can be unambiguously inferred
from the destination type of the expression ?  Is this an
``implementation detail'' ?


Cheers,
Christian

^ permalink raw reply	[flat|nested] 25+ messages in thread

end of thread, other threads:[~2008-04-23 11:22 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <3085.22076015851$1208722372@news.gmane.org>
2008-04-21  3:23 ` Integral conversions in C/C++ Christian Böhme
2008-04-21  8:28   ` Segher Boessenkool
2008-04-21  9:00     ` Christian Böhme
     [not found] <23793.5913996354$1208708537@news.gmane.org>
2008-04-21  0:36 ` Christian Böhme
     [not found] <10044.4877906286$1208659138@news.gmane.org>
2008-04-20 17:57 ` Christian Böhme
2008-04-20 18:16   ` Andrew Haley
2008-04-20 23:07     ` Christian Böhme
2008-04-21 11:48       ` Andrew Haley
2008-04-21 14:18         ` Christian Böhme
2008-04-21 15:55           ` Tom St Denis
2008-04-21 23:51           ` Andrew Haley
2008-04-22 12:33             ` Christian Böhme
2008-04-22 13:30               ` Andrew Haley
2008-04-22 14:11                 ` John Fine
2008-04-22 20:48                   ` Andrew Haley
2008-04-22 21:05                     ` John Love-Jensen
2008-04-23  8:45                       ` Christian Böhme
2008-04-23  2:30                   ` Christian Böhme
2008-04-23 11:22                     ` Andrew Haley
2008-04-24 11:30                       ` John Love-Jensen
2008-04-22 22:42                 ` Christian Böhme
2008-04-23 11:11                   ` Andrew Haley
2008-04-20  6:11 Christian Böhme
  -- strict thread matches above, loose matches on Subject: below --
2008-04-20  4:58 Tom St Denis
2008-04-20  4:49 Christian Böhme

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).