Cast not reported by compiler

In the following program:

void setup() {
  Serial.begin(115200);
  char c;
  unsigned int val = 0xffff;
  
  c = val;
  Serial.println(c, DEC);
}

void loop() {

}

the compiler is performing a silent cast by stuffing a 2-byte int into a 1-byte char, which runs the risk of losing data. With the code above, the monitor shows -1. If I change the value of val to 0xff00, it shows 0, while a value of 0x00ff shows -1 again, which does provide clues about how it chops off the byte during the assignment.

My question is: Should the compiler issue at least a warning when it attempts to assign a larger data type into a small data type and, if not, why not?

Because it is clearly spelled out in the standard. Any arithmetic type can be assigned to another without a cast being required.

Should the compiler issue at least a warning when it attempts to assign a larger data type into a small data type...?

Yes. And it does when enabled.

Building your example in 1.5.8...

avr-g++ -c -g -Os -w ...

From the GCC online documents...

-w   Inhibit all warning messages.

Under the Arduino IDE all warnings are disabled.

With version 1.5.8 this is easily changed by modifying platform.txt.

...and, if not, why not?

Folks new to programming are typically overwhelmed. The theory is that forcing them to deal with warnings makes the situation worse.

@KeithRB: Ok. I still think that's a little dangerous.

@Coding Badly:Thanks! I was not aware that I can change that. I don't know where the file is located, but it shouldn't be too hard to find.

Looks like I am mistaken about GCC. I cannot get it to output a warning for your example.

Ah, here we go, it has to be explicitly enabled...

avr-g++ -c -g -Os -Wconversion ...
sketch_nov10a.ino:6:5: warning: conversion to 'char' from 'unsigned int' may alter its value [-Wconversion]

Turns out, Visual C++ is exactly the same. The warning has to be explicitly enabled.

Which is why lint was required. It appears that "assignment causes implicit narrowing conversion" is what lint would have told you.

You can turn warnings on, but that particular one will drive you insane. For example:

char buf [10];

buf [0] = Serial.read ();
sketch_nov11a.ino: In function 'void setup()':
sketch_nov11a.ino:5:24: warning: conversion to 'char' from 'int' may alter its value [-Wconversion]

Is the warning because an implicit cast is required?

Does

char c = (char)Serial.read();

result in the same warning?

That gets rid of the warning. Then you have to work your way through your beloved* String library, eg.

/home/nick/Development/arduino-1.5.8/hardware/arduino/avr/cores/arduino/WString.cpp: In member function 'void String::toLowerCase()':
/home/nick/Development/arduino-1.5.8/hardware/arduino/avr/cores/arduino/WString.cpp:707:18: warning: conversion to 'char' from 'int' may alter its value [-Wconversion]
   *p = tolower(*p);
                  ^

And that was in code that didn't even use String!

  • Or is that "much loved"?

And in a whole lot of other places, eg.

/home/nick/Development/arduino-1.5.8/hardware/arduino/avr/cores/arduino/Arduino.h:106:73: note: in expansion of macro 'bitClear'
 #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
                                                                         ^
/home/nick/Development/arduino-1.5.8/hardware/arduino/avr/cores/arduino/Tone.cpp:159:9: note: in expansion of macro 'bitWrite'
         bitWrite(TCCR0A, WGM01, 1);
         ^
/home/nick/Development/arduino-1.5.8/hardware/arduino/avr/cores/arduino/Arduino.h:105:39: warning: conversion to 'uint8_t {aka unsigned char}' from 'long unsigned int' may alter its value [-Wconversion]
 #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
                                       ^
/home/nick/Development/arduino-1.5.8/hardware/arduino/avr/cores/arduino/Arduino.h:106:73: note: in expansion of macro 'bitClear'
 #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
                                                                         ^
/home/nick/Development/arduino-1.5.8/hardware/arduino/avr/cores/arduino/Tone.cpp:160:9: note: in expansion of macro 'bitWrite'
         bitWrite(TCCR0B, CS00, 1);
         ^
/home/nick/Development/arduino-1.5.8/hardware/arduino/avr/cores/arduino/Arduino.h:105:39: warning: conversion to 'uint8_t {aka unsigned char}' from 'long unsigned int' may alter its value [-Wconversion]
 #define bitClear(value, bit) ((value) &= ~(1UL << (bit)))

I did know about the Preferences option and turning warnings on. However, as everyone knows, that causes an avalanche of error messages which is worse that no warnings. Rock...hard place...