Skip to content

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.

{ 30 } Comments

  1. Derek Jones | June 4, 2012 at 6:12 am | Permalink

    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. Lee K. | June 4, 2012 at 7:22 am | Permalink

    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. Keith Thompson | June 4, 2012 at 7:32 am | Permalink

    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. Andrey | June 4, 2012 at 7:50 am | Permalink

    Question 4 not accurate. For example in Win64 sizeof(long) == sizeof(unsigned).

  5. Sahil Shah | June 4, 2012 at 9:34 am | Permalink

    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?

  6. Jessie | June 4, 2012 at 10:02 am | Permalink

    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. :-)

  7. regehr | June 4, 2012 at 10:08 am | Permalink

    Hi Jesse (and others), I’ll just repeat the that platform information is specified at the top of the quiz…

  8. anonymous | June 4, 2012 at 10:50 am | Permalink

    “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”).

  9. regehr | June 4, 2012 at 12:29 pm | Permalink

    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.

  10. anonymous | June 4, 2012 at 4:52 pm | Permalink

    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.

  11. Dave G | June 4, 2012 at 5:42 pm | Permalink

    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).

  12. regehr | June 4, 2012 at 6:52 pm | Permalink

    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.

  13. Magnus | June 4, 2012 at 9:58 pm | Permalink

    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.

  14. AstralStorm | June 5, 2012 at 5:12 am | Permalink

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

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

  15. PREMNATH R | June 5, 2012 at 5:31 am | Permalink

    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.

  16. L1964 | June 5, 2012 at 8:34 am | Permalink

    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.

  17. Brian | June 5, 2012 at 9:44 am | Permalink

    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.

  18. adversed | June 5, 2012 at 11:40 am | Permalink

    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…

  19. Rick N | June 5, 2012 at 1:36 pm | Permalink

    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.

  20. RD | June 5, 2012 at 6:22 pm | Permalink

    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.

  21. regehr | June 5, 2012 at 6:33 pm | Permalink

    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

  22. paca | June 6, 2012 at 12:04 am | Permalink

    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 :-)

  23. regehr | June 6, 2012 at 1:39 am | Permalink

    Hi paca, actually this quiz is only for programmers who make mistakes. You go!

  24. Matthew Russotto | June 6, 2012 at 10:30 am | Permalink

    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)

  25. regehr | June 6, 2012 at 10:34 am | Permalink

    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.

  26. Alan8 | June 6, 2012 at 3:21 pm | Permalink

    Nice quiz and learning experience. Thanks!

  27. ARUL | June 6, 2012 at 11:36 pm | Permalink

    INTERESTING!!!! LEARN FEW THINGS

  28. Aravind Parvathala | June 7, 2012 at 2:35 am | Permalink

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

    Great quiz though, learnt a few things.

  29. Al Kyda | June 7, 2012 at 3:53 pm | Permalink

    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.

  30. regehr | June 7, 2012 at 4:04 pm | Permalink

    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.

{ 3 } Trackbacks

  1. » C Portability Gotcha Deprogramming | June 4, 2012 at 2:02 pm | Permalink

    […] weekend I came across this quiz about integers in C by John Regehr, and it reminded me of a bug I encountered last […]

  2. Quiz time « cartesian product | June 5, 2012 at 5:56 am | Permalink

    […] loves a quiz – so here’s one on integer maths in C. I got 10/20 fully correct (i.e. ignoring the ‘partial credits’) – which […]

  3. […] Los que han hecho pruebas de inteligencia deben reconocerlo, en este caso se trata de identificar qué tienen en común los dibujos en todas las cajitas de la izquierda. Bien. ¿Qué tienen en común todas las cajitas de la derecha? Usualmente yo no salgo tan mal en este tipo de pruebas. Por lo general estas pruebas consisten en identificar cuál es el siguiente dibujo en una secuencia. También puede ser el siguiente número en una secuencia de números. Por ejemplo, cuál es el siguiente número en la siguiente secuencia: 1,2,3,5,7,11… La respuesta es fácil, debe ser 13 porque la lista contiene solamente números primos. Pero, ¿y en esta lista? ¿cuál es el siguiente? 2,10,12,16,17… Creo que la prueba original llega hasta el 16 pero la estoy poniendo más fácil. El punto es que no pude resolver en tiempo razonable (¿2 minutos?) la prueba Bongard #38. Y peor aún, abandoné en la pregunta #4 esta prueba de conocimiento sobre lenguaje C. […]