(0x41u*0x201)&0x7FFF undefined?

F

Francois Grieu

Hello,

does the expression
(0x41u*0x201)&0x7FFF
yield the well defined value 0x0241, or is the behaviour undefined?

In other words: what's the type of the product on an unsigned by an
int, and does the use of constants make a change ?

Thanks for helping me fully understand typedness of expressions.

François Grieu
 
M

Malcolm McLean

Francois Grieu said:
does the expression
(0x41u*0x201)&0x7FFF
yield the well defined value 0x0241, or is the behaviour undefined?
In other words: what's the type of the product on an unsigned by an
int, and does the use of constants make a change ?
Thanks for helping me fully understand typedness of expressions.

Bare integer are of type int.
Normally an int has at least 32 bits, so the code is fine.
If int should be 16 bits, you get an overflow. If the int is signed, this is
undefined behaviour. In practise any non-perverse compiler would give you a
compile time diagnostic because the expression is a constant. For exactly
how a perverse compiler would act you can look at the dots and tittles of
the standard.

However your integers are unsigned - hex is by default. So the overflow is
well defiend and has to be a wrapround.
 
F

Flash Gordon

Malcolm McLean wrote, On 21/01/07 09:58:
Bare integer are of type int.

Unless they do not fit in to an int.
Normally an int has at least 32 bits, so the code is fine.

Depends on your definition of "normally". There are more embedded
systems than non-embedded systems (each desktop/notebook contains more
than one embedded system!) and it is quite common for embedded systems
to have 16 or 24 bit ints.
If int should be 16 bits, you get an overflow.

Wrong. Since 0x41u is an unsigned int and 0x201 is a signed int 0x201
will be converted to an unsigned int and no overflow will occur (the
operation is defined as wrapping without invoking overflow). The same
applies to the &.
> If the int is signed,

If? int is signed by *definition*.
> this is
undefined behaviour. In practise any non-perverse compiler would give you a
compile time diagnostic because the expression is a constant. For exactly
how a perverse compiler would act you can look at the dots and tittles of
the standard.

However your integers are unsigned - hex is by default.

Where in the standard does it say that? I can't find it.
> So the overflow is
well defiend and has to be a wrapround.

Well, you reach the correct conclusion although it is for the wrong reasons.
 
F

Francois Grieu

Normally an int has at least 32 bits, so the code is fine.

In this group, normality is MAXINT >=32767
If int should be 16 bits, you get an overflow. If the int is signed, this is
undefined behaviour. In practise any non-perverse compiler would give you a
compile time diagnostic because the expression is a constant. For exactly
how a perverse compiler would act you can look at the dots and tittles of
the standard.

However your integers are unsigned - hex is by default.

That seems incorrect to me. My reading of the standard is that 0x201
is a (signed) int, not an unsigned int.

6.4.4 constant: "the type of an integer constant is the first
of the corresponding list in chich its value can be represented"

Suffix Decimal constant Octal or Hecadecimal constant
none int int
long int unsigned int
long long int long int
unsigned long int
long long int
unsigned long long int

u or U unsigned int unsigned int
unsigned long int unsigned long int
unsigned long long int unsigned long int
unsigned long long int
(..)


I hope I get the type of constants right, but I admit I am allways
confused with the type of expressions, and what can be safely assumed
about expressions that overflow.


François Grieu
 
B

Ben Bacarisse

Malcolm McLean said:
Bare integer are of type int.

If by "bare" you mean integer constants with no 0 or 0x prefix and no
suffix (u/l/ul/lu/ll/ull/llu and their uppercase equivalents) then
they may also be of type long int or long long int if the magnitude of
the constant requires it.
However your integers are unsigned - hex is by default. So the overflow is
well defiend and has to be a wrapround.

No. With a 0 or 0x prefix an un-suffixed integer constant is signed
if it will fit into a signed int (or into a long int or long long
int). The only different caused by the prefix is that it *may* be
taken as being an unsigned int (or the long or long long versions) if
it fits in one.
 
B

Ben Bacarisse

Francois Grieu said:
does the expression
(0x41u*0x201)&0x7FFF
yield the well defined value 0x0241, or is the behaviour undefined?

I think so. 0x41u is of type unsigned int and 0x201 is of type int.
In other words: what's the type of the product on an unsigned by an
int, and does the use of constants make a change ?

The signed int will be promoted to unsigned before the multiply. Hex
constants (with no suffix) will be takes as the smallest one of:

int
unsigned int
long int
unsigned long int
long long int
unsigned long long int

that can represent the value.
 
S

santosh

Francois said:
Hello,

does the expression
(0x41u*0x201)&0x7FFF
yield the well defined value 0x0241, or is the behaviour undefined?

The calculation will yield a well defined value but it may not be
0x0241. It depends on the range of the types involved in the
expression. For unsigned types, the behaviour is based on modulo 2^n.
Thus for large values, the result will wrap-around, but according to
the C standard, this is well defined, even if it may not be what you
want. Use sufficiently large types to ensure no wrap-around. limits.h
contains the necessary range values for the integral types for your C
implementation.
In other words: what's the type of the product on an unsigned by an
int, and does the use of constants make a change ?

Where's an unsigned value multiplied by a signed one? Just use the u or
ul or ull suffix to force a particular type for the constants.
 
C

Clark S. Cox III

Francois said:
Hello,

does the expression
(0x41u*0x201)&0x7FFF
yield the well defined value 0x0241, or is the behaviour undefined?

In other words: what's the type of the product on an unsigned by an
int,

The first thing that you must understand is that before any
multiplication can take place, the compiler converts both operands to
the same type. The type chosen (for integers) is the first type in the
following list that can represent the value:

int
unsigned int
long
unsigned long
long long
unsigned long long

In this case, the int operand will be converted to an unsigned int, and
the two unsigned int operands will then be multiplied. The same then
happens with the '&' operator.

The same conversion happens with other types as well:

short s = 15;
long l = 20;
long l2 = l * s;
/* s's value is converted to long before
the multiplication takes place
*/
and does the use of constants make a change ?

No.
 
F

Francois Grieu

"Clark S. Cox III said:
The first thing that you must understand is that before any
multiplication can take place, the compiler converts both operands to
the same type. The type chosen (for integers) is the first type in the
following list that can represent the value:

Can't get it: what value? First type that can hold any value
that each operand could take given its type ?
int
unsigned int
long
unsigned long
long long
unsigned long long


In this case, the int operand will be converted to an unsigned int,

I'm willing to agree with this conclusion, but can't reach it applyingthe
above rule: int can hold -1, but unsigned int cannot.



Francois Grieu
 
F

Francois Grieu

"santosh said:
The calculation will yield a well defined value but it may not
be 0x0241.

How could that be ? If the product is performed using unsigned type
(which I now tend to beleive is the case), the product can overflow,
but the overall value is still precisely defined.
And If the product was evaluated using signed type, it can overflow,
and overflow on signed cause undefined behaviour (e.g. exception),
does not it ?

Where's an unsigned value multiplied by a signed one?

0x41u*0x201. 0x41u is unsigned, 0x201 is signed. At least I'm
relatively confident on this part.


Francois Grieu
 
F

Francois Grieu

"santosh said:
Where's an unsigned value multiplied by a signed one?

0x41u is the unsigned value
0x201 is the signed value

The calculation will yield a well defined value but it may
not be 0x0241.

Following an answer I understand, I beleive this is wrong
 
K

Keith Thompson

Francois Grieu said:
does the expression
(0x41u*0x201)&0x7FFF
yield the well defined value 0x0241, or is the behaviour undefined?

In other words: what's the type of the product on an unsigned by an
int, and does the use of constants make a change ?

There have been a lot of wrong answers in this thread. I'll try very
hard not to generate another one.

The constant 0x41u is of type unsigned int, because of the 'u' suffix.
(Without the 'u', it would be of type signed int.)

The constant 0x201 is of type (signed) int. A hexadecimal integer
constant's type is the first of:
int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
in which its value can be represented; 0x201 (513) is guaranteed to
fit in an int.

0x41u * 0x201 multiplies an unsigned int by a signed int. When two
operands of differing type are multiplied, the "usual arithmetic
conversions" are first applied. The rules take about a page of text
to describe fully. In this case, the signed int operand is implicitly
converted to type unsigned int.

The result of 0x41u * 0x201 has the value 33345 (0x8241) and the type
unsigned int. Since unsigned int is guaranteed to be able to
represent values in the range 0 to 65535, the result is representable
directly as an unsigned int; no wraparound is necessary. (33345 might
overflow a signed int, but that's not relevant here.)

The constant 0x7FFF (32767) is of type (signed) int, since its value
is always representable in that type. The "usual arithmetic
conversions" are applied to the operands of the unary "&" operator.
The left operand has value 0x8241 and type unsigned int. The right
operand has value 32767 and type signed int, and is implicitly
converted to unsigned int. The result has the value 0x241 (decimal
577), and type unsigned int.
 
C

Chris Torek

There have been a lot of wrong answers in this thread. I'll try very
hard not to generate another one.

Indeed :)
The constant 0x201 is of type (signed) int. A hexadecimal integer
constant's type is the first of:
int
unsigned int
long int
unsigned long int
long long int
unsigned long long int
in which its value can be represented ...

Note that the rules changed between C89/C90 and C99. Part of the
change is obvious -- C89/C90 did not have "long long" -- but if I
I remember correctly off-hand, some other details changed as well.

One's best bet, in general, is to use suffixes to force the desired
type everywhere. (In the case of the original expression, the single
"U" suffix in 0x41U is sufficient to force the entire sequence of
operations to be done in "unsigned int", as Keith Thompson describes
in the [unquoted] rest of the article.)
 
P

Peter Nilsson

Chris said:
Indeed :)


Note that the rules changed between C89/C90 and C99. Part of the
change is obvious -- C89/C90 did not have "long long" -- but if I
I remember correctly off-hand, some other details changed as well.

The change was with respect to unsuffixed decimal constants. In C90,
the list was int, long, unsigned long; in C99 it became int, long, long
long.
Under C99 an unsuffixed decimal constant cannot result in an
unsigned type (except by implementation extension).

[A trap for young players: all constants are positive irrespective of
the
suffix. A leading minus is an unary operator.]
 
F

Francois Grieu

Keith Thompson said:
0x41u * 0x201 multiplies an unsigned int by a signed int. When two
operands of differing type are multiplied, the "usual arithmetic
conversions" are first applied. The rules take about a page of text
to describe fully. In this case, the signed int operand is implicitly
converted to type unsigned int.

Many thanks for the explanation. I was misinterpreting the standard
on this part. I'm now figuring the sense of the applicable rules,
in section 6.3.1.8: (..when deealing with integer types..)
the integer promotions are performed on both operands. Then the
following rules are applied to the promoted operands:
If both operands have the same type, then no further conversion
is needed.
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.
-> 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.
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.

When dealing with 0x41u*0x20, we are in the case marked with ->
because of this extract of 6.3.1.1 (..)
the rank of any unsigned integer type shall equal the rank
of the corresponding signed integer tupe, if any.


Francois Grieu
 
C

Clark S. Cox III

Francois said:
Can't get it: what value? First type that can hold any value
that each operand could take given its type ?

Should be : "...represent the values". That is, the values of the two
operands.
 
K

Keith Thompson

Clark S. Cox III said:
Should be : "...represent the values". That is, the values of the two
operands.

That's misleading. The type of the result does not depend on the
values of the operands, only on the types of the operands.
 

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,774
Messages
2,569,598
Members
45,161
Latest member
GertrudeMa
Top