My 'favourite' bit of surprising (not undefined) behaviour I've seen recently in the C11 spec is around infinite loops, where<p>void foo() { while (1) {} }<p>will loop forever, but<p>void foo(int i) { while (i) {} }<p>is permitted to terminate...even if i is 1:<p>> An iteration statement whose controlling expression is not a constant expression, that performs no input/output operations, does not access volatile objects, and performs no synchronization or atomic operations in its body, controlling expression, or (in the case of a for statement) its expression-3, may be assumed by the implementation to terminate<p>To make things a bit worse, llvm can incorrectly <i>both</i> of the above terminate - <a href="https://bugs.llvm.org//show_bug.cgi?id=965" rel="nofollow">https://bugs.llvm.org//show_bug.cgi?id=965</a>.
I'll be honest, I didn't find any of these to be particularly surprising. If you've been using C and are familiar with strict-aliasing and common UB issues I wouldn't expect any of these questions to seriously trip you up. Number 2 is probably the one most people are unlikely to guess, but that example has also been beaten to death so much since it started happening that I think lots of people (Or at least, the people likely to read this) have already seen it before.<p>I'd also add that there are ways to 'get around' some of these issues if necessary - for example, gcc has a flag for disabling strict-aliasing, and a flag for 2's complement signed-integer wrapping.
Honestly, Optimizing compilers will kill C.<p>It killed the one thing C was good at - simplicity (you know exactly what happens where, note I'm not saying speed, as C++ can be quite a bit faster than C).<p>Now, due to language lawyering, you can't just know C and your CPU, you have to know your compiler (and every iteration of it!). And if you slip somewhere, your security checks blow up (<a href="http://blog.regehr.org/archives/970" rel="nofollow">http://blog.regehr.org/archives/970</a> <a href="https://bugs.chromium.org/p/nativeclient/issues/detail?id=245" rel="nofollow">https://bugs.chromium.org/p/nativeclient/issues/detail?id=24...</a>) .
I don't think this Q&A format makes for a good case of not knowing C.<p>I mean I got all answers right without thinking about them too much, but would I too if I had to review hundreds of lines of someone else's code? What about if I'm tired?<p>It's easy to spot mistakes in isolated code pieces, especially if the question already tells you more or less what's wrong with it. But that doesn't mean you'll spot those mistakes in a real codebase (or even when you write such code yourself).
It's worth noting that for example #12, the assert will only fire for debug builds (i.e. the macro NDEBUG is not defined). So, depending on how the source is compiled, it may be able to invoke the div function with b == 0.
C also: <a href="https://news.ycombinator.com/item?id=12902304" rel="nofollow">https://news.ycombinator.com/item?id=12902304</a>
IMHO the problem is with compilers (and their developers) who think UB really means they can do <i>anything</i>, when what programmers usually expect is, and the standard even notes for one of the possible interpretations of UB, "behaving during translation or program execution in a documented manner characteristic of the environment".<p>Related reading:<p><a href="http://blog.metaobject.com/2014/04/cc-osmartass.html" rel="nofollow">http://blog.metaobject.com/2014/04/cc-osmartass.html</a><p><a href="http://blog.regehr.org/archives/1180" rel="nofollow">http://blog.regehr.org/archives/1180</a> and <a href="https://news.ycombinator.com/item?id=8233484" rel="nofollow">https://news.ycombinator.com/item?id=8233484</a>
1. Unless C's variable definition rules are completely different from C++'s, int i; is a full definition, not a declaration. If both definitions appear at the same scope (e.g. global), this will cause either a compiler error or a linker error. A variable declaration would be extern int i;
As a former C programmer, you know not to fool around at the max bounds of a type. That avoids all of the integer overflow/underflow conditions. When in doubt, you just throw a long or unsigned on there for insurance. :)
I got every single one right. Does that mean I know C through and through? Perhaps. But all of these are the 'default' FAQ pitfalls of C, not the really tricky stuff.
I made this post as a response. Disclaimer: yet another programming language trying to dethrone C. People seem to be less enthusiastic about the subject these days.<p><a href="http://andrewkelley.me/post/zig-already-more-knowable-than-c.html" rel="nofollow">http://andrewkelley.me/post/zig-already-more-knowable-than-c...</a>
I feel bad because I'm smart enough to answer these questions correctly in a quiz format<i></i>, but if I saw any of them in production code, I would not even think twice about it.<p><i></i> (the quiz questions themselves lead you on, plus I read the MIT paper on undefined behavior that was posted on here back in 2013)
I'm sorry, but the answer this website gives to 1. is wrong. See for yourself:<p><pre><code> int i;
int i = 10;
int main(int argc, char* argv[]){
return 0;
}
</code></pre>
Try to compile it. It doesn't work (gcc.exe (GCC) 5.3.0), the error is:<p><pre><code> a.cc:2:5: error: redefinition of 'int i'
int i = 10;
^
a.cc:1:5: note: 'int i' previously declared here
int i;
^
</code></pre>
Either I misunderstood the author and this example, or I do know C.