I like to think I know C well enough. I’ve read K&R cover to cover, and I’ve done my fair share of C hacking over the years. But I’ve learned that with C, you have to be prepared, always, and at all times, to eat humble pie. I feel compelled to share this whopper of a slice that came steaming hot from Van Der Linden – which I’ve now determined should be required reading for anyone even thinking about ever going near C.

#include "stdio.h"

int main(int argc, char *argv[]) {
    unsigned int x = 1;
    if(-1 < x)
        printf("yes\n");
    else
        printf("no\n");
    return 0;
}

Simple enough? WRONG. When a binary operation is invoked on two incompatible types (in this case, an unsigned int and an int), the “usual arithmetic conversions” apply.

Time to put on that language lawyer hat. According to the C99 rules:

If the operand that has unsigned integer type has rank greater than or equal to the rank of the type of the other operand, the operand with signed integer type is converted to the type of the operand with unsigned integer type.

Rank?

The rank of any unsigned integer type is equal to the rank of the corresponding signed integer type, if any.

Which means, of course, that -1 is “promoted”, at least on the x86-64 platform. And you can be damn sure that 0xFFFFFFFF when considered 4,294,967,295 decimal, is greater than one. Now imagine that your unsigned int definition lives in some other translation unit, long, long ago and far, far away. No, -Wall will not save you.

Another psychopathic killer: automatic string concatenation. Take the following code:

#include "stdio.h"

int main(int argc, char *argv[]) {
    char *config[] = {
        "a man ",
        "a plan ",
        "a canal "
        "panama ",
    };
 
    printf("%lu\n", sizeof(config)/sizeof(config[0]));
    printf("%s\n", config[2]);

    return 0;
}

Do you see the bug? I’ve misplaced the comma, which should come after “a canal ” instead of “panama “. Don’t let that final comma fool you: the C compiler just ignores it. However, the C compiler is just jonesing to remove that NUL terminating char ‘\0’ from ‘a canal \0’ and append ‘panama \0’, in which case you’ve just wound up with three, not four, config parameters; and with ‘a canal panama\0’ as your third config entry.

Happy bug hunting!

  • exDM69

    Automatic concatenation of string literals is a super useful feature, especially when writing some macros that need to generate some strings at compile time (e.g. I do this to generate some shader sources in 3d programming). Sure, you can misuse it or make subtle but deadly bugs with it. However, compile time string concatenation is so useful (there’s no runtime cost) that it’s value outweighs it’s drawbacks.

  • David Júlio

    -Wall will not save you but -Wextra helps (or -Wsign-compare if you want just that warning). -Wall, despite its name, doesn’t really enable all types of warnings. http://gcc.gnu.org/onlinedocs/gcc-4.6.2/gcc/Warning-Options.html

    • http://twitter.com/atomklein Adam Klein

      Thanks for the tip – helpful!

  • Anonymous

    The potential problems outlined here are simple to trace and correct, there are far greater problems to be found on platforms and in libraries and operating systems. These faults can waste days and even weeks of work in tracing and writing work rounds. Writing in C you know to be careful.

    • Anonymous

      Agreed, these aren’t the most common problems by far. But it’s not paranoia to consider what lurks in the dark corners.

      • Anonymous

        It is not paranoia. However, writing a small memory management system was the only cure for one platform interface problem and, as we use C, it was possible. There can be benefits even though it can be prickly.

  • David

    Come on, have you never heard of “lint”?

    http://www.gimpel.com/html/index.htm

    Yes it looks expensive but what is your bug worth. (I tried it on both examples and it found the problems)

    BTW if you think that problem was hard to find try Gimpel’s bug of the month.

    • David

      OK I just asked around the office, and several people have never heard of lint(OK I’m the only one). So maybe it’s not as well known as I thought. 🙁

      People if you write in C/C++ use lint it WILL keep you out of so much trouble.

      • Anonymous

        Yep, heard of lint. -Wall is supposed to do 80% of what lint does, and is free. I use PyLint extensively. It seems per the first comment that -Wsign-compare does the trick.

        • David

          even if -Wall (or -Wextra) get 80% it’s the other 20% that would still worry me. Please have a look at the Gimple site and try and compile some id the bug of the months Puzzle, see how many you can get to compile with -Wall. it’s quite worrying

          • Anonymous

            Great site, I’ll keep it bookmarked.

  • R Caloca

    That book is my favorite best hidden treasure. It goes through all the nitty gritty in a fun, educational way.

  • Ddbug

    Use lint. Knowing about lint “required for anyone even thinking about ever going near C”.

© 2014 Adam Klein's Blog Suffusion theme by Sayontan Sinha, modified by Adam :)