I am new to C and recently ran into some trouble with mismatching data types and their memory allocation. I am writing a very simple program to calculate the xor checksum o
Comparing types of the same signedness but different size with one-another works, as the smaller type is extended to the larger type. Comparing types of different signedness is problematic as you could get wrong results if the signed type is not larger than the unsigned type and the signed number is negative. It is a good idea to make sure the signed number is not negative at first:
signed_t a;
unsigned_t b;
/* instead of */
if (a < b)
/* ... */
/* use */
if (a < 0 || a < b)
/* ... */
The warnings about comparison between signed and unsigned integers (and other arithmetic operations), stem from the implicit conversions that occur when two operands of unlike type are combined with an operator.
There is a good chapter on this issue in the manual that accompanies the PC-Lint tool from Gimpel.
A reading of the available C standards documents in particular "integer promotions" is helpful.
eg in http://www.open-std.org/jtc1/sc22/WG14/www/docs/n1256.pdf (C99) - section 6.3.1 "Arithmetic operands"
In particular, "if an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int"
Hence in such a context, "-1" will get converted to binary all-ones [implementation-dependent] as an unsigned number - potentially giving surprising results to the unwary. eg an unsigned integer quantity divided by integer "-1" will give zero.
The answer there is to cast the unsigned to a signed value before the arithmetic.
Note that sizeof() returns an unsigned value.
The C standard states that the long type is large enough to represent the constant LONG_MAX, which must be at least 2147483647 (231-1). If we take this lower bound as the value of LONG_MAX, then it's possible that it isn't large enough. It's one less than 2 GiB, after all.
ssize_t isn't in the C standard, but is defined in the POSIX standard. It must be large enough to represent the constant SSIZE_MAX, which must be at least 32767 (215-1). Don't rely on this type either.
On my machine, long and ssize_t are both 4 bytes. You can verify the sizes yourself using the sizeof operator. You may get different results. If you want your program to be portable, don't rely on something implementation-specific.
Lastly, if you really don't want to use those typedefs, I recommend using the unsigned long long type. It's large enough to represent the constant ULLONG_MAX, which must be at least 18446744073709551615 (264-1).
See also: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/limits.h.html