What is the C++ type conversion precedence?

P

Peng Yu

Hi,

Please see the following code and the output. It seems that if one of
%'s oprand is unsigned, the other will also be converted to unsigned.

There is a operator precedence table in wikipedia. I'm wondering what
is the general rule in type conversions.

Thanks,
Peng

#include <iostream>

int main() {
std::cout << -10 % 3 << std::endl;
std::cout << -10 % static_cast<unsigned>(3) << std::endl;
std::cout << static_cast<unsigned>(-10) % static_cast<unsigned>(3)
<< std::endl;
std::cout << 10 % 3 << std::endl;
}

$./main-g.exe
-1
0
0
1
 
P

Peng Yu

* Peng Yu:



Yes. Usual promotion of arguments. In the standard known as the "usual
arithmetic conversions".

I tried to write a simplified explanation here but it seems the rules are not
amenable to simplification.

But the general idea is an automatic promotion up to some common type that
ideally should be able to represent all possible values of both arguments.

In the case of "-10 % static_cast<unsigned>(3)", I would think it is
as reasonable to convert it to
"-10 % static_cast<int>(static_cast<unsigned>(3))" as to
"static_cast<unsigned>(-10) % static_cast<unsigned>(3)".

But why C++ choose the latter one?
 
R

red floyd

Peng said:
In the case of "-10 % static_cast<unsigned>(3)", I would think it is
as reasonable to convert it to
"-10 % static_cast<int>(static_cast<unsigned>(3))" as to
"static_cast<unsigned>(-10) % static_cast<unsigned>(3)".

But why C++ choose the latter one?

Because that's what the Standard says to do. Probably because that's
how C did it.
 
J

James Kanze

On Jul 17, 1:53 pm, "Alf P. Steinbach" <[email protected]> wrote:
In the case of "-10 % static_cast<unsigned>(3)", I would think
it is as reasonable to convert it to "-10 %
static_cast<int>(static_cast<unsigned>(3))" as to
"static_cast<unsigned>(-10) % static_cast<unsigned>(3)".

Reasonable doesn't count for much here. All that really counts
is the standard.
But why C++ choose the latter one?

Because that's what C did? And C choose the latter because they
had to choose one. Depending on the application, it is
sometimes better to preserve sign, and sometimes better to
preserve value. From my imperfect memory (and thus to be taken
with a grain of salt): K&R didn't really make it clear which one
was to be preferred, and early compilers varied (although if
memory serves me right, Johnson's pcc---the first C compiler to
"escape" from Bell Labs---preserved value). So no matter what
the C committee chose, it would break some code. I don't really
remember any of the arguments, but one thing that does occur to
me: the conversion of signed to unsigned is always well defined;
the conversion of unsigned to signed is implementation defined
(and may result in an implementation defined signal). While in
your example, it's obvious what the first would mean, try:
-10 - static_cast< unsigned >( -3 )
Rewriting it according to your first suggestion results in
implementation defined behavior (and possibly a signal);
rewriting it according to the second is well defined (for a
given size of int).

The whole thing is a mess, and the basic rule is to use int
unless there is a very strong reason to do otherwise, and to
limit unsigned types to cases where you need the modulo
arithmetic, or are doing bit manipulations (so that >> is well
defined), or are accessing raw memory (as unsigned char). An
even more important rule, however, is not to mix signed an
unsigned, so faced with a poorly designed library, which uses
unsigned types for other things (like the number of elements in
an array), you should stick with unsigned types when interfacing
with it. (In sum, a real PITA.)
 

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
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top