c = a + b and implicit conversion -
with compiler, c
54464 (16 bits truncated) , d
10176. gcc
, c
120000 , d
600000.
what true behavior? behavior undefined? or compiler false?
unsigned short = 60000; unsigned short b = 60000; unsigned long c = + b; unsigned long d = * 10;
is there option alert on these cases?
wconversion warns on:
void foo(unsigned long a); foo(a+b);
but doesn't warn on:
unsigned long c = + b
first, should know in c standard types not have specific precision (number of representable values) standard integer types. requires minimal precision each type. these result in following typical bit sizes, standard allows more complex representations:
char
: 8 bitsshort
: 16 bitsint
: 16 (!) bitslong
: 32 bitslong long
(since c99): 64 bits
note: actual limits (which imply precision) of implementation given in limits.h
.
second, type operation performed determined types of operands, not type of left side of assignment (becaus assignments expressions). types given above sorted conversion rank. operands smaller rank int
converted int
first. other operands, 1 smaller rank converted type of other operand. these usual arithmetic conversions.
your implementation seems use 16 bit unsigned int
same size unsigned short
, a
, b
converted unsigned int
, operation performed 16 bit. unsigned
, operation performed modulo 65536 (2 power of 16) - called wrap-around (this not required signed types!). result converted unsigned long
, assigned variables.
for gcc, assume compiles pc or 32 bit cpu. this(unsigned) int
has typically 32 bits, while (unsigned) long
has @ least 32 bits (required). so, there no wrap around operations.
note: pc, operands converted int
, not unsigned int
. because int
can represent values of unsigned short
; unsigned int
not required. can result in unexpected (actually: implementation defined) behaviour if result of operation overflows signed int
!
if need types of defined size, see stdint.h
(since c99) uint16_t
, uint32_t
. these typedef
s types appropriate size implementation.
you can cast 1 of operands (not whole expression!) type of result:
unsigned long c = (unsigned long)a + b;
or, using types of known size:
#include <stdint.h> ... uint16_t = 60000, b = 60000; uint32_t c = (uint32_t)a + b;
note due conversion rules, casting 1 operand sufficient.
update (thanks @chux):
the cast shown above works without problems. however, if a
has larger conversion rank typecast, might truncate value smaller type. while can avoided types known @ compile-time (static typing), alternative multiply 1 of wanted type:
unsigned long c = ((unsigned long)1u * a) + b
this way larger rank of type given in cast or a
(or b
) used. multiplication eliminated reasonable compiler.
another approach, avoiding know target type name can done typeof()
gcc extension:
unsigned long c; ... many lines of code c = ((typeof(c))1u * a) + b
Comments
Post a Comment