Monday, April 2, 2012

GCC lossy conversion warnings for C and C++

Have you ever been bitten by the bug where you, for example, return a long long from a function, but set the return type of the function to int (by mistake)? I sure have, and off the top of my head, I can remember this bug costing me a failed solution at least twice at TopCoder. Just to make this more concrete, here's a simple example function that has this problem.

int foo() {
  long long x = 1LL<<42;
  return x;
}

This kind of conversion is actually perfectly legal (for example, by section 4.7 of C++11 n3337), and the result is implementation-defined if the target type (here int) is signed and can't represent the value of the source type (here long long). GCC defines the result to be the value modulo 2^n such that it fits into the type, but what they actually mean is that the lower however-many bits are kept and the rest is discarded, which makes sense in two's complement (which is what GCC and the large majority of "conventional" systems use). So if int is 32-bit, and long long is 64-bit, you get the lower 32-bits of the original value. In this specific case, the result would therefore be zero.

Now, you'd really like to be warned about this kind of thing (at least I would :), but you don't get that with neither -Wextra (a.k.a. -W) nor -Wall. It turns out you have to explicitly ask for it using -Wconversion. The argument they make for code that intentionally does these kinds of conversions (without casts) is definitely valid, but I will be adding this flag to my default set for sure, at least for TopCoder :).