C: Unsigned vs signed, short vs int
Posted: Thu Aug 23, 2012 6:08 am
In the 3d edition of C Programming Language Mr Stroustrup said: "Prefer a plain int over a short int or a long int" and "Using an unsigned instead of an int to gain one more bit to represent positive integers is almost never a good idea". Why? I have made some investigation and found these:
1) Do not mix unsigned and signed in the arithmetic expressions, since if there is a comparison
then you can have a bug. For example:
This function always print ">6", since b is converted to unsigned then added with a (result is a huge value since is treated as unsigned) and finally compared with unsigned 6.
To fix this replace "a + b > 6" with "(int)a + b > 6". But to guard yourself from this annoying bug always use signed type for variables that you want to use as numbers (and do all math you need in obvious way) and use unsigned type only if you intend to use this variable as bitmask.
OK, it is clear for me now.
2) Choose the minimal integer type that can hold all possible values of your variable, i.e: if my variable will be 0..300 that I should use short. 0..65535 then I should use int (not unsigned short! See item1) . There is one exception in this rule: use int (which represents word size of CPU) for loop counters and similar (i.e. for variables that are used in loops).
I agree with this. But what about putc (int ch)? In docs I see "ch will be converted to unsigned char" Why not "putc (unsigned char ch)"? And often I see "outportb(int port, unsigned val)" instead of "outportb(int port, unsigned char val)". The second variant looks natural for me. May be they want to improve a performance (to get the unsigned char arg from the stack into 32-bit register compiler need generate movzx instead of mov)?
1) Do not mix unsigned and signed in the arithmetic expressions, since if there is a comparison
then you can have a bug. For example:
Code: Select all
void foo(void)
{
unsigned int a = 6;
int b = -20;
(a + b > 6) ? puts(">6") : puts("<=6");
}
To fix this replace "a + b > 6" with "(int)a + b > 6". But to guard yourself from this annoying bug always use signed type for variables that you want to use as numbers (and do all math you need in obvious way) and use unsigned type only if you intend to use this variable as bitmask.
OK, it is clear for me now.
2) Choose the minimal integer type that can hold all possible values of your variable, i.e: if my variable will be 0..300 that I should use short. 0..65535 then I should use int (not unsigned short! See item1) . There is one exception in this rule: use int (which represents word size of CPU) for loop counters and similar (i.e. for variables that are used in loops).
I agree with this. But what about putc (int ch)? In docs I see "ch will be converted to unsigned char" Why not "putc (unsigned char ch)"? And often I see "outportb(int port, unsigned val)" instead of "outportb(int port, unsigned char val)". The second variant looks natural for me. May be they want to improve a performance (to get the unsigned char arg from the stack into 32-bit register compiler need generate movzx instead of mov)?