24 ms·
If anyone is curious, on gcc 12.3.0 and clang 16.0.6 (x86_64), the answers are what most people (who have written lots of C) would expect: 1) 8 2) 0 3) 160
by LatticeAnimal 3y ago
If anyone is curious, on gcc 12.3.0 and clang 16.0.6 (x86_64), the answers are what most people (who have written lots of C) would expect:
1) 8
2) 0
3) 160
4) 1 (both clang and gcc output a warning)
5) 2 (only clang outputs a warning)
While I like the idea of this quiz, I think it would be more powerful if it provided examples of compilers / architectures where these are not the correct answers. (I also think thorough unit tests would catch most of these errors)
- Farmadupe 3y agoThe author is making a deliberate point about undefined behaviour in the article. Hence them not executing worked examples. In fact, by not doing so they are making a subtle implicit statement that it is uninteresting to consider actually attempting to execute these snippets. The third paragraph of the "P.S" of the article (you have to press submit to see it) is the one that really gives the game away.
- ryao 3y agoMost of these things are implementation defined rather than undefined. Only the 5th is undefined.
- 1000100_1000101 3y agoMore than implementation defined, for some you need context that simply isn't given. On the ones with mixed-type structs, even if you know what system it's compiled for you don't know if someone has used pragma pack 1 to byte pack the data instead of standard packing. Just seeing the struct, you still don't know.
- LatticeAnimal 3y agoI agree that in theory it would be cool to have C code that uses only defined behavior and works on all platforms for all eternity. However, I think most programs have a fairly clear understanding of what platforms (OS+arch) they are targeting and what compilers they are using to target those platforms. If the compiler has defined behavior (and you have unit tests for that behavior) on all of these platforms, I don't think it is a huge deal. (Ideally you wouldn't... but sometimes its an accident or unavoidable) As an example, while struct padding (problem 1) might not technically be in the spec, it is a cornerstone of FFI and every new compiler (that supports C FFI) has a way to compile structs with the same padding. To my original point, if the article had instead given examples of compilers + architectures that produced different answers, I might feel differently. However, just saying mentioning that these weird edge cases are undefined (in the spec) doesn't mean much to me.
- ryao 3y agoMy answers for 2, 3 and 5 were different: 2) I thought the type would be promoted to short. It turns out that the result of the arithmetic operation is promoted to int. 3) The signness of char is platform dependent. It is signed on x86 and amd64, but unsigned everywhere else. After seeing my mistake, I would expect this to cause the answer to be -96 on amd64 from sign extension when it converted into an integer, yet it is 160, which is what I would have expected from a platform where char is signed. If anyone knows why it is 160 here, please let me know. 5) This is a classic. I know to answer I do not know because despite having an Operator Precedence, C famously says that this is undefined. I have no idea why the standard does this when there is a clearly right answer. Java for example makes this have only 1 right answer.
- erhaetherth 3y agoCan you explain 3? A space is 20 IIRC, 2013 is 260. An unsigned char tops out at 255 but I guess this one is* signed so... that's 127. And then I have no idea what happens, some kind of overflow, but I don't know the wrapping rules.
- jbeninger 3y agoI made the same mistake having worked with URL encoding for so long. " " is 20...in hex.
- defrost 3y ago" " is a C string constant ... so a space encoding followed by a NUL encoding.
- ryao 3y ago' ' is 0x20 or 32.
- defrost 3y agoor 0x40 .. or something else. https://en.wikipedia.org/wiki/EBCDIC https://en.wikipedia.org/wiki/EBCDIC
- deleted 3y ago[deleted]
- not2b 3y agoThe case with multiple increments in an expression might produce different results depending on optimization level, perhaps not in this case but in other cases. That is because the compiler is allowed to use any order, so the order it picks might depend on what is in the registers.
- erhaetherth 3y ago5) How does 2 make sense? Shouldn't be 0 + 1? Or does the pre-increment take precedence over the addition, thus the left i is 1 but not because of the post-increment?
- deleted 3y ago[deleted]
- P-Nuts 3y agoTo get 2, there are (at least) a couple of ways it can happen, we can do i=0,i++ and get LHS=0, now i=1,++i and get RHS=2. Or we can do i=0,++i and get RHS=1, then i=1,i++ and get LHS=1. However we’re also allowed to do something like this: i=0, a=i, b=i, b=b+1, RHS=b (RHS=1), LHS=a (LHS=0), a=a+1, i=a, i=b. Probably quite a lot of other things are allowed to happen. Usual disclaimer that a standard-compliant compiler is allowed to vaporise your cat etc as part of UB. The thing to Google is “sequence points”.