18

In the following program, the line 5 does give overflow warning as expected, but surprisingly the line 4 doesn't give any warning in GCC: http://www.ideone.com/U0BXn

int main()
{
    int i = 256;
    char c1 = i;    //line 4
    char c2 = 256;  //line 5
    return 0;
}

I was thinking both lines should give overflow warning. Or is there something I'm missing?


The topic which led me to do this experiment is this: typedef type checking?

There I said the following(which I deleted from my answer, because when I run it, it didn't show up as I had expected):

//However, you'll get warning for this case:

typedef int  T1;
typedef char T2;

T1 x = 256;     
T2 y = x; //possible overflow warning! (but it doesn't give warning :()
Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • What warning level you set at? VS gives warnings for such things (ANY time you try to assign a large->small without cast) but only if you crank up the warning level to max. – Edward Strange Feb 23 '11 at 18:46
  • @Crazy: I expect warnings in both cases. But GCC doesn't give in one case, even when I compile it with `-Wall` compiler option! – Nawaz Feb 23 '11 at 18:48
  • -Wconversion is what you want to add. -Wall unintuitively does not indicate turn on all warnings :\ http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html – Edward Strange Feb 23 '11 at 18:56
  • @Crazy: Please post that as answer. I'll accept it :D – Nawaz Feb 23 '11 at 19:00

4 Answers4

13

-Wall doesn't include many options. -Wconversion is one of them and warns about the behavior you're interested in.

See http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

Edward Strange
  • 40,307
  • 7
  • 73
  • 125
  • It didn't warn for me in g++ 4.2 which is why I didn't mention this. – Mark B Feb 23 '11 at 19:16
  • 1
    hmm...I assumed Nawaz verified before asking me to post as answer. 3.4 doesn't seem to care either. Based on the documentation I'd certainly expect it to. int->char is definitely a conversion to smaller type. – Edward Strange Feb 23 '11 at 19:40
  • and @Mark: Yes, it's giving warning with GCC 4.5.0 – Nawaz Feb 23 '11 at 19:45
11

In the general case of assigning an int value to a char object, the compiler doesn't know whether the int is out of range of the char.

Look at the actual warning more closely:

warning: overflow in implicit constant conversion

It is in this specific case, where a constant is being converted to char that the compiler is able to warn you. Likewise, if you changed the declaration of i to be const:

const int i = 256;

you will also get the warning, because the value being assigned to c2 is a constant expression.

Note also that the warning is somewhat misleading as the conversion does not technically "overflow." Arithmetic overflow yields undefined behavior in C++. A narrowing conversion (like int to char, if int has a larger range than char) yields some implementation-defined conversion.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 2
    But compiler should give warning if we assign `int` to `char`, as there can be possible loss of data! – Nawaz Feb 23 '11 at 18:47
  • @Nawaz: Well, that would be a different sort of warning. The warning you are getting for `c1` is saying "the value **is** out of range for the target type." The warning you want for `c2` is something like "the value **might be** out of range for the target type." As for why gcc doesn't warn for that, I don't know (I don't use gcc on a regular basis). Visual C++ quite happily reports "warning C4242: 'initializing' : conversion from 'int' to 'char', possible loss of data." – James McNellis Feb 23 '11 at 18:52
  • @Nawaz I suspect this is because in C `int` was used in pretty much any function where `char` would be used in C++. Thus warning on the conversion could result in huge amounts of warnings on legacy C code. I can't find any `-W` style option to enable such a warning though. – Mark B Feb 23 '11 at 18:52
  • @MarkB: It is common in C to use unsigned types to represent members of abstract algebraic rings (which wrap) rather than numbers (which shouldn't); an 8-bit unsigned char would be equivalent to Z256, each element of which is a set of integers which are equivalent mod 256. For each integer or element of a larger power-of-two ring type, there will be exactly one element of a smaller power-of-two ring type can result from conversion, but the reverse is not true. Thus, larger rings should implicitly convert to smaller, but not vice versa. Unfortunately... – supercat Feb 10 '14 at 21:21
  • @MarkB: Neither C nor C++ provides any way of declaring whether a particular value of an unsigned integer type should be interpreted as a number or a ring. – supercat Feb 10 '14 at 21:21
1

Post GCC 4.3, the semantics of -Wconversion have been updated to detect implicit conversions that might change a value, but you have to enable -Wsign-conversion as well, because otherwise you won't get a warning for code that might change the sign of a number due to coercion between signed and unsigned types.

Contrary to what Crazy Eddie is saying, prior to GCC 4.3 (which hadn't been released yet at the time) -Wconversion didn't generically check for problems introduced by implicit type conversion and the like. Rather, it checked whether your program would behave differently than it would have behaved if it had used old-style K&R function prototypes.

This not only meant that it didn't give a warning on all implicit type conversion / coercion problems, but it also meant that some good code gave an unnecessary warning. And of course, you'd get no error with g++ because such prototypes aren't valid C++ anyway.

Anonymous
  • 21
  • 1
1

Well, line 5 is an obvious error that any compiler can see directly, and always an error. Line 4 would require at least some data flow analysis to discover the error. Perhaps this isn't done with the settings used at the site, or perhaps the compiler writers didn't consider this important enough to figure it out.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • It is immediately obvious that 'char x = 256' is an error, if you know that CHAR_MAX is less that 256. To realize that 'x = i' always is an error, you must first figure out what values i could have. – Bo Persson Feb 23 '11 at 20:40
  • 1
    Consider `unsigned short x = 65536`. It is not immediately obvious whether or not this is an error since the size of short can vary from compiler to compiler. Technically, the same is actually true of `char`, though a size of 8 bits is almost universal. There ARE platforms/compilers for which a `char` is capable of holding the value 256. Thus line 5 is not "**always** an error", as you say. – Ponkadoodle Oct 01 '13 at 18:31
  • See this question for more on *non-8* bit bytes: [what platforms have something other than 8 bit char?](http://stackoverflow.com/questions/2098149/what-platforms-have-something-other-than-8-bit-char) – SlySven Mar 30 '16 at 13:36