conversions

M

Mark

Hello

still drilling the conversions topic, and I can't entirely conceive a few
paragraphs from the Standard. Let us consider a couple of cases:

(1)
char c;
int i;
c + i => We have two objects of integral types, so as per 6.3.1.8 integral
promotion results in (int)c + i. Following 6.3.1.8p1, what is applied
further:

"If both operands have the same type, then no further conversion is needed"

or

"Otherwise, if both operands have signed integer types or both have unsigned
integer types, the operand with the type of lesser integer conversion rank
is converted to the type of the operand with greater rank."

(1)a
int i;
short int j;
i + j => i + (int)j. The same question as in (1) applies for this case.

(2)
unsigned int i;
int j;
i + j => Promotion results in i + (unsigned int)j and then according to
6.3.1.8p1

"..if the operand that has unsigned integer type has rank greater or equal
to the rank of the type of the other operand, then the operand with signed
integer type is converted to the type of the operand with unsigned integer
type"

we have (unsigned int) i + (unsigned int) j. Seems to be correct to me?

(2)a
unsigned int i;
unsigned short int j;
i + j => i + (unsigned int)j and voila.

(3)
unsigned int u;
long int p;
u + p => this is a tricky case. I guess if the the size(long) == sizeof(int)
, integer promotion will end up u + (unsigned int)p. But what if
sizeof(long) > sizeof(int) ?

I think enough examples by now. Please correct my thoughts when wrong.
Thanks.
 
J

James Kuyper

Mark said:
Hello

still drilling the conversions topic, and I can't entirely conceive a
few paragraphs from the Standard. Let us consider a couple of cases:

(1)
char c;
int i;
c + i => We have two objects of integral types, so as per 6.3.1.8
integral promotion results in (int)c + i

Not quite; if CHAR_MAX > INT_MAX, then the integer promotions result in
the equivalent of (unsigned)c + i. This is rather unlikely, but not
impossible, there have been machines which used 16-bit char, and
machines which used 16-bit int; I'm not sure if there are any that have
used both.
. Following 6.3.1.8p1, what is
applied further:

"If both operands have the same type, then no further conversion is needed"

If CHAR_MAX <= INT_MAX, both operands have the type 'int', so this is
the clause that applies.
or

"Otherwise, if both operands have signed integer types or both have
unsigned integer types, the operand with the type of lesser integer
conversion rank is converted to the type of the operand with greater rank."

This never applies. If UCHAR_MAX > INT_MAX, since the conversion rank of
unsigned int is equal to the conversion rank of int, this is the
relevant clause:

"Otherwise, if the operand that has unsigned integer type has rank
greater or equal to the rank of the type of the other operand, then the
operand with signed integer type is converted to the type of the operand
with unsigned integer type."

Therefore, in that case it's equivalent to (unsigned)c + (unsigned)i.
(1)a
int i;
short int j;
i + j => i + (int)j. The same question as in (1) applies for this case.

Both operands have the same type, 'int', so you're done.
(2)
unsigned int i;
int j;
i + j => Promotion results in i + (unsigned int)j and then according
to 6.3.1.8p1

"..if the operand that has unsigned integer type has rank greater or
equal to the rank of the type of the other operand, then the operand
with signed integer type is converted to the type of the operand with
unsigned integer type"

we have (unsigned int) i + (unsigned int) j. Seems to be correct to me?
Correct.

(2)a
unsigned int i;
unsigned short int j;
i + j => i + (unsigned int)j and voila.

If USHORT_MAX > INT_MAX, then it's actually i + (unsigned)(int)j. If
j>INT_MAX when it gets converted to int, "either the result is
implementation-defined or an implementation-defined signal is raised."
(6.3.1.3p3), so this does make a difference.

I've used machines where short and int were both 16 bits, so this is not
nearly as unlikely a situation as CHAR_MAX > INT_MAX.
(3)
unsigned int u;
long int p;
u + p => this is a tricky case. I guess if the the size(long) ==
sizeof(int) , integer promotion will end up u + (unsigned int)p. But
what if sizeof(long) > sizeof(int) ?

Neither u nor p is affected by the integer promotions, they apply only
to one of the following:

"— An object or expression with an integer type whose integer conversion
rank is less
than or equal to the rank of int and unsigned int.
— A bit-field of type _Bool, int, signed int, or unsigned int." (6.3.1.1p2)

Since the conversion rank of the signed type is higher than the rank of
the unsigned type, the relevant clauses are:

"Otherwise, if the type of the operand with signed integer type can
represent all of the values of the type of the operand with unsigned
integer type, then the operand with unsigned integer type is converted
to the type of the operand with signed integer type.

Otherwise, both operands are converted to the unsigned integer type
corresponding to the type of the operand with signed integer type."

Note that it does not depend upon the sizes of the type, but the range
of values that they can represent. In this case, if LONG_MAX >=
UINT_MAX, the result is (long)u + p. However, if LONG_MAX < UINT_MAX,
then the result is (unsigned long)u + (unsigned long)p.
 
J

James Kuyper

James Kuyper wrote:
....
If USHORT_MAX > INT_MAX, then it's actually i + (unsigned)(int)j. If

My apologies; I managed to confuse myself while putting together that
response. You are correct, it is i + (unsigned)j. Ignore everything else
I said about that case.

I should have realized that I must have made a mistake: the usual
arithmetic conversions happen automatically, and therefore, as a matter
of deliberated and very careful design, are never lossy, and produce
implementation-specific results only insofar as they produce results
that depend upon the values (such as INT_MAX) that are
implementation-defined. The way in which the result depends upon those
values is very strictly defined by the standard. The more dangerous
conversions must be explicitly requested, by the use of a cast expression.
 
M

Mark

James Kuyper wrote:
[snip]

Thanks ofr your valuable commentaries.
Neither u nor p is affected by the integer promotions, they apply only
to one of the following:

"— An object or expression with an integer type whose integer
conversion rank is less
than or equal to the rank of int and unsigned int.
— A bit-field of type _Bool, int, signed int, or unsigned int."
(6.3.1.1p2)

So, if we consider a typical platform, where such relation holds (taken from
C FAQ):

sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <= sizeof(long
long)

then only 'char', 'signed char', 'unsigned char', 'short int' are subject to
integer promotions?
Since the conversion rank of the signed type is higher than the rank
of the unsigned type, the relevant clauses are:

Where in 6.3.1.1 it is spelled out, if any? I can't find relevant clause.
I also heard about "value preserving" and "unsigned preserving" rules, which
are applied to a 'unsigned type' being converted to a larger type. When
exactly these rules are applied? I guerss somewhere along the lines quoted
below:
 
J

James Kuyper

Mark said:
James Kuyper wrote:
[snip]

Thanks ofr your valuable commentaries.
Neither u nor p is affected by the integer promotions, they apply only
to one of the following:

"— An object or expression with an integer type whose integer
conversion rank is less
than or equal to the rank of int and unsigned int.
— A bit-field of type _Bool, int, signed int, or unsigned int."
(6.3.1.1p2)

So, if we consider a typical platform, where such relation holds (taken
from C FAQ):

sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <=
sizeof(long long)

It would be perfectly legal for sizeof(short) > sizeof(long) - but it
would imply at least one byte's worth of padding bits. The correct
relationships are in terms of the ranges covered by the types, not in
terms of the sizes of the types:

UCHAR_MAX <= USHORT_MAX <= UINT_MAX <= ULONG_MAX <= ULLONG_MAX
SCHAR_MAX <= SHORT_MAX <= INT_MAX <= LONG_MAX <= LLONG_MAX
SCHAR_MIN >= SHORT_MIN >= INT_MIN >= LONG_MIN >= LLONG_MAX

(Note: the above are mathematical statements of ordering, and NOT C
expressions).
then only 'char', 'signed char', 'unsigned char', 'short int' are
subject to integer promotions?

In C99, _Bool is also promoted, along with any extended integer types
supported by an implementation that have lower conversion rank than int.
Where in 6.3.1.1 it is spelled out, if any? I can't find relevant clause.

You've snipped some of the context, which may lead to confusion. I was
not talking about signed and unsigned types in general. I was talking
about the specific signed type "long int", and the specific unsigned
type "unsigned int". The relevant sections of 6.3.1.1 are therefore:

"The rank of long long int shall be greater than the rank of long int,
which shall be greater than the rank of int, ..."

"The rank of any unsigned integer type shall equal the rank of the
corresponding signed integer type, if any."

Since the signed type corresponding to 'unsigned int" is "int", they
must have the same rank. Since the rank of "long int" is higher than the
rank of "int", it must also be greater than the rank of "unsigned int".
I also heard about "value preserving" and "unsigned preserving" rules,
which are applied to a 'unsigned type' being converted to a larger type.
When exactly these rules are applied? ...

"value preserving" and "unsigned preserving" are not separate rules;
they are characteristics of the rules I cited.

If you read the conversion rules carefully, you will find that the
standard always requires that if a value can be represented in a given
type, the result of converting that value to that type must preserve the
value. When the conversion involves a floating point type, it might not
be possible to preserve the value exactly, but the standard does require
that the resulting value be one of the two representable values that
bracket the original value.
... I guerss somewhere along the lines
quoted below:

"unsigned preserving" refers to the idea that unsigned types dominate
signed type, which is reasonable, given the fact that conversion from a
signed value to an unsigned type has standard-defined semantics, while
the semantics of converting a signed value to an unsigned type is
sometimes implementation-defined, and can result in the raising of a signal.

The clause quoted above is actually an example of how C is NOT always
unsigned preserving, since the result when it applies is a value of
signed type. Another example is the integer promotions: if an unsigned
type has values that can all be represented in an int, it promotes to
int, not unsigned int. That's OK, because those conversions are safe.

However, C does have one key rule that is "unsigned preserving", and it
immediately follows the paragraph cited above:

"Otherwise, both operands are converted to the unsigned integer type
corresponding to the type of the operand with signed integer type."
 
B

Ben Bacarisse

James Kuyper said:
Mark said:
James Kuyper wrote:
[snip]

Thanks ofr your valuable commentaries.
Neither u nor p is affected by the integer promotions, they apply only
to one of the following:

"— An object or expression with an integer type whose integer
conversion rank is less
than or equal to the rank of int and unsigned int.
— A bit-field of type _Bool, int, signed int, or unsigned int."
(6.3.1.1p2)

So, if we consider a typical platform, where such relation holds
(taken from C FAQ):

sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long) <=
sizeof(long long)

It would be perfectly legal for sizeof(short) > sizeof(long) - but it
would imply at least one byte's worth of padding bits. The correct
relationships are in terms of the ranges covered by the types, not in
terms of the sizes of the types:

UCHAR_MAX <= USHORT_MAX <= UINT_MAX <= ULONG_MAX <= ULLONG_MAX
SCHAR_MAX <= SHORT_MAX <= INT_MAX <= LONG_MAX <= LLONG_MAX
SCHAR_MIN >= SHORT_MIN >= INT_MIN >= LONG_MIN >= LLONG_MAX

(Note: the above are mathematical statements of ordering, and NOT C
expressions).
then only 'char', 'signed char', 'unsigned char', 'short int' are
subject to integer promotions?

In C99, _Bool is also promoted, along with any extended integer types
supported by an implementation that have lower conversion rank than
int.

A nit: the integer promotions are applied to values whose types have a
rank less than *or equal to* that of int (and unsigned int).

As a result of this, when UINT_MAX == INT_MAX, unsigned int promotes
to int. On such an implementation you won't be able to do unsigned
shifts, for example. (I am just clarifying: I know you know this
because you quote the rule later on.)

Of course, such a situation is very odd and probably only likely to
arise on a machine that can't do unsigned arithmetic in any "natural"
way. In that context the rule makes sense.

<snip>
 

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