views:

94

answers:

5

Hi, I am having following doubt regarding "int" flavors (unsigned int, long int, long long int).

When we do some operations(* , /, + , -) between int and its flavors (lets say long int) in 32bit system and 64bit system is the implicit typecast happen for "int"

for example :-

int x ; long long int y = 2000;

x = y ; (Higher is assigned to lower one data truncation may happen) I am expecting compiler to give warning for this But I am not getting any such warning. Is this due to implicit typecast happen for "x" here. I am using gcc with -Wall option. Is the behavior will change for 32bit and 64bit.

Thanks Arpit

+2  A: 

If you are worried, you can include <stdint.h> and use types with defined lengths, such as uint16_t for a 16-bit unsigned integer.

Borealid
+1  A: 

See http://gcc.gnu.org/ml/gcc-help/2003-06/msg00086.html -- the code is perfectly valid C/C++.

You might want to look at static analysis tools (sparse, llvm, etc.) to check for this type of truncation.

reece
Well, GCC folks at times aren't really a helpful lot... /me thinks about gcc and strict aliasing rules. /me shivers.
Dummy00001
+7  A: 

-Wall does not activate all possible warnings. -Wextra enables other warnings. Anyway, what you do is a perfectly "legal" operation and since the compiler can't always know at compile-time the value of the datum that could be "truncated", it is ok it does not warn: programmer should be already aware of the fact that a "large" integer could not fit into a "small" integer, so it is up to the programmer usually. If you think your program is written in not-awareness of this, add -Wconversion.

ShinTakezou
Yes, amongst other thingss, -Wconversion will tell you when you implicitly convert a larger type to a smaller type. The Apple branch of gcc also has `-Wshorten-64-to-32`.
JeremyP
+1 for -Wconversion.
Dummy00001
+3  A: 

Casting without an explicit type cast operator is perfectly legal in C, but may have undefined behavior. In your case, int x; is signed, so if you try to store a value in it that's outside the range of int, your program has undefined behavior. On the other hand, if x were declared as unsigned x; the behavior is well-defined; cast is via reduction modulo UINT_MAX+1.

As for arithmetic, when you perform arithmetic between integers of different types, the 'smaller' type is promoted to the 'larger' type prior to the arithmetic. The compiler is free to optimize out this promotion of course if it does not affect the results, which leads to idioms like casting a 32bit integer to 64bit before multiplying to get a full 64bit result. Promotion gets a bit confusing and can have unexpected results when signed and unsigned values are mixed. You should look it up if you care to know since it's hard to explain informally.

R..
Nice answer, but I tend to avoid "implicit casting". Casting by definition is explicit. Conversion is implicit or explicit.
Alok
Is the new wording better?
R..
@R: I am not so sure. The problem here (as you note in your answer) is the types involved, casting and conversion don't come into the picture at all. The same undefined behavior would exist whether there was a cast or a conversion. Given `long x = 200000; int i = x; int j = (int)x;`, both the assignments to `i` and `j` have a (potential) problem.
Alok
+2  A: 

Your code is perfectly valid (as already said by others). If you want to program in a portable way in most cases you should not use the bare C types int, long or unsigned int but types that tell a bit better what you are planing to do with it.

E.g for indices of arrays use always size_t. Regardless on whether or not you are on a 32 or 64 bit system this will be the right type. Or if you want to take the integer of maximal width on the platform you happen to land on use intmax_t or uintmax_t.

Jens Gustedt