KJH KJH - 1 month ago 18
C Question

Just calling in to complain

About C. Mind you, I love C - I do everything in it. But just now I encountered this gem:

// opening a file and expecting a certain size of it.
unsigned char buf[ sizeof(sometype) ];
struct stat s;
//.. open file, do fstat
if (s.st_size != sizeof(buf)) {
}


And I get a warning from GCC: Comparing signed and unsigned. So sizeof() (gcc) returns a different type than s.st_size (libc).

Sorry about the complaint. I got a few beers in me and I encountered this and it is simply infuriating: they should both be unsigned.

Answer

This is more of a POSIX consistency issue than a C problem:

  • The st_size member of the stat structure is the file size expressed in bytes and has type off_t, out of consistency with other POSIX functions that use a (potentially negative) byte offset into a file.
  • This type is signed and although it does not make much sense to have a negative file size, a negative value could indicate that the file size cannot be computed.
  • The main issue regarding this member is its range: it used to be a 32 bit long and this caused headaches when files larger that 2GB or even 4GB became more common.

gcc is warning about potential signed / unsigned comparisons because the semantics of such expressions are obscure to many people, underwent subtle changes in the course of normalisation and produce potentially counterintuitive results.

In your case, I am sure you are well aware you can get rid of the warning by casting one of the other arguments, but you should beware that off_t and size_t might have different sizes, and they do in 32-bit environments, so casting s.st_size as (size_t) is incorrect:

if (s.st_size != (off_t)sizeof(buf)) {
}

You might argue that off_t might be smaller than size_t, but it is unlikely. In any case, there is a way to avoid the cast, if gcc does not complain about mixing signed and unsigned expressions in simple arithmetics, you can write:

if (s.st_size - sizeof(buf) != 0) {
}

Finally, disabling the warning would be counter productive as it is usually a good hint about a real problem. Using all the help you can get from the compiler by turning on most warnings (gcc -Wall -W or clang -Weverything) is a good habit.