A Quiz About Integers in C

The C language's rules for integer operations have some quirks that can make even small programs behave in confusing ways. This post is a review of these rules in the form of a quiz containing 20 questions. I recommend going through the questions in order. If you are a beginning C programmer, you should consult a C book as you go through these questions since there are a lot of little things (such as what "1U" means) that I have not bothered to explain. If you are a serious C programmer, I expect you'll do well -- this quiz is not intended to be extremely difficult. You should assume C99. Also assume that x86 or x86-64 is the target. In other words, please answer each question in the context of a C compiler whose implementation-defined characteristics include two's complement signed integers, 8-bit chars, 16-bit shorts, and 32-bit ints. The long type is 32 bits on x86, but 64 bits on x86-64 (this is LP64, for those who care about such things). Summary: Assume implementation-defined behaviors that Clang / GCC / Intel CC would make when targeting LP64. Make no assumptions about undefined behaviors.
Start
You scored %%SCORE%% out of %%TOTAL%%. Note: Sometimes scores are reported incorrectly -- sorry about that. I think it's a bug in the quiz plugin for WP that I'm using. I hope you found this quiz to be useful and/or entertaining, and please write a comment or mail me if you find a mistake. As I said in the introduction, it was intended to be easy for experienced C programmers. In reality, integer bugs are hard to avoid not so much because the individual issues are extremely complicated, but rather because integer operations are everywhere and their corner case bugs get mixed in with algorithmic difficulties and other programming problems. I have another integer quiz in the works that will be more difficult.
Your answers are highlighted below.

83 thoughts on “A Quiz About Integers in C”

  1. Question 5 contains two identifiers whose values are implementation defined (i.e., SCHAR_MAX and CHAR_MAX) and an equality comparison. The result is either 0 or 1, i.e., the result is unspecified.

    Question 17: the status of x – 1 + 1 depends on the order of evaluation and can be undefined is 1 is subtracted from x rather than 1 being added to 1. It is common practice to consider the undefined to dominate and call the result undefined.

    Question 18: if the quiz is about what the C Standard says then (short)x+1 is only defined for some values of x if it has type int. Re: comment #33 if we need to take the authors experience into account the answer can be almost anything and spoils the point of the quiz.

    Question 20: Something more sensible would be:
    What is the value of: sizeof (unsigned short)-1

    with possible answers:

    a: 1
    b: 2
    c: 4

  2. Question 18 is wrong: if x > SHORT_MAX or x < SHORT_MIN, then (short) x is undefined and so is (short) x + 1. So (short) x + 1 is defined for some values of x, not all, when x is int.

    Question 5 is implementation-defined, and saying it's x86 of x86-64 is not sufficient. I got it wrong since I answered "undefined".

  3. Re #18, conversion of an out-of-range value from int to short is *not* undefined behavior. It yields an implementation-defined result or raises an implementation-defined signal. (The
    latter permission was added in C99; I know of no compiler that takes advantage of it.) But the front page mentions several implementation-specific assumptions; the result of this conversion is not among them.

  4. In Q.17, won’t the compiler after the abstract syntax tree creation, during optimization, evaluate +1-1=0 and replace it with 0 before evaluating the entire expression?

  5. I want to call foul on a couple of these!

    In #5, the explanation basically says that “undefined” is the right answer but you’re assuming a standard x86 PC.

    In #11-15, we don’t know the size of any of these types. For #12, for example, sizeof(int) could well be 64. UNICOS comes to mind.

    (If we’re to assume these questions only apply to a particular platform, then it should say that; if we’re to assume only the C language, then these answers aren’t right.)

    All of this leads me to believe that the few simple rules I have, when I need to write in C, have treated me very well over the years: (1) never assume booleans are anything other than zero and nonzero, (2) never use unsigned types, and (3) if you need integers greater than 10,000, get a bignum library. 🙂

  6. “I’ll just repeat the that platform information is specified at the top of the quiz…”

    I’ll repeat: the information is NOT at the top of the quiz. The information is on the page when you first land, but DISAPPEARS when you open the quiz.

    Obviously you approved the previous comment, but maybe you didn’t actually read it since:

    (a) you didn’t fix it

    and (b) you’re still using false language (AFAICT it’s impossible to have it on the page at the same time as the quiz, so it is NOT “at the top of the quiz”).

  7. Hi anonymous, you’re right, it’s at the top of the post containing the quiz.

    As my colleague Matt Might likes to say: There’s always someone in the world who will take exception to anything you do. The Internet helps you find that person.

  8. I’m not pointing this out idly.

    I’m pointing this out because the comments here are fillled with people who don’t seem to have noticed it, and I’m pointing out a particular, FIXABLE reason they might be doing so.

    Your job as a writer is to communicate with your readers. If you fail to communicate to a large number of your readers, you need to stop blaming them and consider that maybe your UX is actually flawed.

  9. I’m a bit surprised about Question 18. Question 5 mentions that overflowing a signed integer is undefined behaviour, and others have pointed out that conversion to a signed integer type that cannot hold the value gives implementation-defined behaviour. We’re given some assumptions about architecture but no assumptions about any particularly implementation (of which there are many for the given architecture).

  10. Hi Dave G, every modern C implementation that I am aware of chooses to define the integer down-casting behavior to be truncation, so I figured this could safely be considered to be a side effect of “assume LP64”. But yes, it would have been better to state this explicitly.

    You should not equate this implementation defined behavior with an undefined behavior such as signed overflow. That is a totally different beast.

  11. I’m slightly amused at the people who are angry that THEY didn’t read the instructions 🙂

    I got 78% but 20/20 yay! The quiz gives the correct result if you don’t pick the right answer after having picked the wrong one.

    I understood immediately the questions I got wrong. This makes me want even more that C/C++ compilers catch undefined behaviour whenever they can when compiled with debug settings.

  12. Congratulations on killing platforms where sizeof(int) < 4.
    The signed char question was likewise mean.

    Everyone using ARM (esp. Thumb) now must hate you. 😉

  13. This is very interesting. I’ve learned a lot about C integers. This will be very helpful in programming either in C or in any other language.

  14. Very instructive.

    I didn’t get all the answers right, because my last C program is some 20 years ago and probably C99 is the 1999 implementation of ANSI C, which is far away from my conception of C. My knowledge is basically derived from K&R C with some book knowledge of ANSI C.

  15. An excellent quiz. Made me realize why I tended toward the use of unsigned 64-bit integers and avoided the corner cases as needed. Math and C are a dangerous combination.

  16. About question 9 (x << 0) I bet common compilers would simplify it into a no-op even with the lowest optimisation level… But if the standard says it is undefined behviour, people say something really odd is going to happen likely. (If the "likely" means on 1% of compilers on 1% of hardware, no matter: it is still undef behaviour, so compilers should make it behaves badly, just to be aligned – ok undef behaviour states a "contract" the programmer can trust, and in this case he can't… 1% of the time, at least). This also suggests that we are dealing with logical shift rather than arithmetic shift (which should be always well defined). So, always do your bit games with unsigned…

  17. I graduated from the University of Utah with a computer science degree back in the70’s and I do not recall any detail instructions on integers. But then, the C programming language did not exist or was too new.

  18. A lot of times, when confronted with such situations, I would look at the assembly language the compiler generated to see if it was doing what I wanted.

  19. Hi RD, I do that too.

    But you have to be really careful with undefined behavior since the next time you upgrade your compiler, change optimization options, or even recompile after changing some unrelated code, the assembly language corresponding to the undefined code may do something totally different. For an example, see the comments starting at #3 here:

    http://blog.regehr.org/archives/722

  20. I’ve been programming and using C for 40 years.
    None of these questions came up in my professional experience.
    Never had a bug in my programs related to these issues.
    If one of these questions comes up and disqualifies me in a job interview, I do not want that job 🙂

  21. Q18: (short)x + 1 is implementation-defined (and may raise a signal), because (short)x is implementation-defined and may raise a signal if x is outside the range of short — see 6.3.1.3.3

    Q20: Since INT_MIN/-1 (which would be one greater than INT_MAX assuming twos-complement) is not representable as an int, INT_MIN % -1 is undefined (6.5.5.6)

  22. Hi Matthew, I’ve read the “multiplicative operators” part of the C99 standard very carefully and do not believe that your interpretation is the most reasonable one. They fixed the language in C11.

  23. As stated scoring doesn’t take into account which attemp the correct answer was arrived at.

    Great quiz though, learnt a few things.

  24. For #4, actual program output in my quick test was 1 for both x86 and x64 — so I guess either the answer is wrong or gcc is buggy.

  25. Hi Al, the answer to #4 is correct, as are a few versions of GCC that I tried. If you provide more detail I can try to repro your result.

Comments are closed.