Type Conversions

Implicit Type Conversions

Bad news: C does not care much about widths and signs

  • Assignment to narrower types simply cuts off

  • Sign propagation is undefined

  • Sign may change across signed/unsigned assignments

  • ⟶ History is full of integer overflow bugs, sign bugs etc.

  • GCC (and other compilers) has options that warn on possible type-bugs (can be very loud though)

Rules are not easy to comprehend - especially the Why behind ⟶ Examples …

Sign Bugs

Unsigned to signed, same width

unsigned int ui = 4294967295U;
int i = ui;

The other way around: signed to unsigned

int i = -1;
unsigned int ui = i;

Attention

This is desired behavior from the very beginning ⟶ no compiler error, no compiler warning!

Though at least GCC can be convinced to warn:

  • -Wsign-conversion

  • more global: -Wconversion

Truncation

unsigned long ul = 4294967296U;
unsigned int ui = ul;
  • Unscrupulous conversion (by brutal truncation) of a 64 bit number (0x100000000) to a 32 bit number

  • ui == 0

Note

-Wconversion

Sign Propagation

char c = '\310';
int ic = c;
  • char is signed on x86_64

  • c == -56

Note

-Wconversion

Conversion Using Operators

Hard rule

If an operator gets passed different types, then the “weaker” is converted to the “stronger” - the result is of the “stronger” type.

What does that mean? (disregarding unsigned)

  • If one operand is long double, then the other is converted

  • else, if one is double, …

  • else, if one is float, …

  • else, char and short are converted to int

  • int is the default type for arithmetic operations

Conversion and unsigned (1)

Hard rule. There is no hard rule. Well almost:

When mixing unsigned and signed integers of the same width, then signed is converted to unsigned

Warning

Gosh!

Additionally: widths are hardware defined!

-1L < 1U
  • True: 1U becomes 1L

  • -1U (unsigned 32) is less than the “stronger” -1L (signed 64)

  • fits in signed 64 losslessly

  • Correct!

-1L < 1UL
  • False: -1L (signed 64) becomes unsigned 64, as dictated by the right hand side.

  • Incorrect!

Warning

This is desired behavior from the very beginning ⟶ no compiler error, no compiler warning!

Though at least GCC can be convinced to warn:

  • -Wsign-conversion

  • more global: -Wconversion

Conversion and unsigned (2)

Beware of mixing!

  • Not a problem if the signed part can never become negative

  • Big problem otherwise!

int x;
unsigned int y;

if (x < y) ...
$ gcc -Wsign-compare ...
warning: comparison between signed and unsigned integer expressions

Compiler Warnings

All that is desired behavior!

  • Read: historical baggage

  • ⟶ compiler warnings have to be explicitly enabled

Option

Meaning

-Wsign-conversion

Sign could change

-Wconversion

Value and sign …

-Wsign-compare

Comparison with mixed signed value

-Wtype-limits

E.g. if (ui >= 0) ...

-Wall

Selection of “good” warnings

-Wextra

… more good warnings

-pedantic

Does not hurt

-Werror

Anti-Sloppiness: warnings become errors

Tip

General advice: the more the better!

Last Warning

C’s datatypes are immensely hazardous. More hazardous is, though:

  • Overengineering

  • Messy design

  • Loosing control over one’s data structures

  • Not knowing ranges of variables

  • Not being open to program modification

Forced Conversion - Cast

Should an automatic conversion be identified as being wrong (e.g. because the compiler warns), it can be overridden

int x;
unsigned int y;

if (x < (signed)y) ...