20 ms·
So you think you know C? (2016)
- ChuckMcM 7y agotl;dr - C has some undefined behavior, if you plan on things working based on your experience with one compiler and one computer, you will be surprised.
- Ididntdothis 7y agoI wonder how many C programmers have experience with writing multi platform/compiler code. I have done a lot of C and C++ but never had to port it so I would not be surprised if I had made a ton of mistakes.
- deleted 7y ago[deleted]
- fantasticFerret 7y agoC programer here. I try to never think assume I know C.
- adamnemecek 7y agoThe tone is insufferable, the test is beyond useless.
- saagarjha 7y ago> And at this point, I only have to apologize. The test is clearly provocative and may even be a little offensive. I’m sorry if it causes any aggravation.
- Ididntdothis 7y agoFailed all of them. I totally agree with what the author is writing. Don’t presume anything but measure. I also tend to code in a way that it’s not necessary to know all the intricacies. Its not as clever as many like and often makes for longer code but is usually easier to read.
- wiml 7y ago> Don’t presume anything but measure. I think that's exactly the wrong takeaway here. Most of these have a well-defined result on a given platform (host + abi). You can measure that result. But it'll be different on a different platform. And the others don't have a well-defined result — a real-world compiler will produce a result, and you can measure that, but it might be different tomorrow. Unless you know the difference between platform-specific behavior and undefined behavior, you don't know which ones to avoid.
- begriffs 7y agoRather: don't presume anything, read the language specification for the version you are writing (C89, C99, etc). "Measuring" is exactly the wrong thing to do because often it is indicative of only your specific architecture/compiler.
- chubot 7y agoOK you tricked me. But the test would have been better if the answer was "undefined behavior" instead of "I don't know".
- badamp 7y agoNot all of them are undefined behavior
- staticassertion 7y agoSure, but "I don't know" makes it seem like you're just saying "pass", which, when you finish the test, is obviously not what it represents.
- wrs 7y agoSad to say I scored perfectly, due to a similar early disillusionment on embedded platforms, and years of pain porting code between 16- and 32-bit architectures when the author thought they knew the size of “int”.
- bcaa7f3a8bbc 7y agoMy score is 3/5. One immediate redflag I have noticed is using "int", "char", "short" as if they have a definite size. They don't. C standard only guarantees a minimum size. For example, many PDPs are 36-bit. Assuming the size of a variable is a common practice nowadays, but at least one should use uint8_t, int32_t, etc. from stdint.h. But I was still tricked, it should be obvious in hindsight, 12 years of schooling led me to think: If the author was asking these questions, at least one or two questions must be answerable (even if it's technically incorrect, but you'd better to guess the original intention of a question). So I still tried to guess and got two wrong answers... Get to be careful next time...
- Raymonf 7y agoIn school, I was taught to choose the "best answer" on a test or quiz, and if you don't know something, choose the answer that looks right to you. This test.. it reverses that entirely.
- gravypod 7y agoUnfortunately the "best answer" is taken to mean "the wrong answer that the teacher programmed into you".
- scarface74 7y agoI only got two out of five. One so really didn’t know and I remembered enough C to remember sequence points.
- NohatCoder 7y agoIt is school that gets it wrong. In real life, knowing that you don't know something and acting accordingly is often way better than taking a guess.
- JKCalhoun 7y ago4/5 here. In fact after the third question provided "I don't know" as an answer I started to suspect something was up — especially since the author said only one answer was the right one ... why even provide "I don't know" then, I wondered? I knew "int" was sort of platform-dependent (was 16-bits generally when I was learning to code, later 32-bit became more typical) — so combined with that niggle and all the "I don't knows", I (correctly) reevaluated by first couple of answers. Still, didn't realize the last one was compiler-dependent.
- icedchai 7y agoI scored perfectly. I've been programming in C since 1989, on various platforms (started with the Amiga, then VAX/VMS, Linux x86, and various embedded systems.)
- danbolt 7y agoAt the end of the test, the author talks about automation programming for a nuclear power plant. I don’t think I could ever sleep the same at night after writing something like that.
- Someone1234 7y agoParticularly writing it in C... It isn't a language well suited to be fully defined (see this very article for why), and no, Rust/Go aren't either. But Ada derivative or Haskell perhaps, there's some amazing tooling for safety critical systems and the languages themselves lend themselves to exposing side-effects.
- pdpi 7y ago> But Ada derivative or Haskell perhaps Ada, maybe? I don't know enough about it to comment. You definitely don't want to use Haskell for that sort of work load, though, at least not directly. Laziness-by-default is precisely the sort of hard-to-reason-about logic you don't want in that sort of application. That said, if I I had no alternative but to try and tackle this problem, I would seriously consider a strategy where I would write a Haskell program that would generate the actual program (potentially in ASM directly) for me.
- OldHand2018 7y ago> I don’t think I could ever sleep the same at night after writing something like that In these situations, you likely know your hardware and know your compiler, so you can actually provide an answer for 4 of the questions. The last one is a situation where someone should tell you not to get cute in the code review. I wrote C in telecom and finance and in both places we enforced a rule: when you define a structure, put a comment after each element that says what you think the structure offset should be, and at the end of the structure #define a constant that says what you think the size of the structure should be. In a code review, if anyone noticed something that didn't look right, you could talk about it. In testing, you could also check that sizeof(foo_s) == FOO_S_SIZE and fail if it wasn't. In some of our code, we would test the size of various types and structures on startup and immediately exit if they weren't what we expected. We'd print type sizes to logs to help debugging if there was ever a problem. We were supporting a single code base that ran on big endian, little endian, X86, Itanium, SPARC, ARM. Compilers change, but automated tests of type and structure sizes catch things immediately. It may sound like a lot of work, but it actually isn't at all. It also helps a lot with long-term maintainability.
- ddingus 7y agoI failed the first couple, rapidly getting into I don't know. Answered the rest, IDK. Laughed! Great exercize.
- Sir_Cmpwn 7y ago5/5 - but I came to Hacker News to procrastinate from the C parser I've been writing.
- NieDzejkob 7y agoWait, which of your projects needs a C parser?!
- Sir_Cmpwn 7y agoA new one
- deleted 7y ago[deleted]
- vkaku 7y agoI answered Idk to all. After the first two, the pattern became clear and I felt like if I wrote a compiler myself, the answers could be very different. I've worked on 16 bit C code, 32 and now 64 bit code. So I knew that the behavior was implementation and optimization dependent. :) Ignorance is bliss in C.
- usr1106 7y agoI failed on one, number 4. I bravely assumed 16 bit integers cannot exist. Can anyone name a concrete platform/compiler where int is/was 16 bit. Or is this just a theoretical option left open by the spec?
- inamberclad 7y agoAVR, so certain Arduinos. On an Arduino Uno, sizeof(int) returns 2.
- segfaultbuserr 7y agoSo does AVR's (ex?) competitor, PIC8. This comes from the documentation of Microchip's C18 compiler. https://i.stack.imgur.com/1uV3l.jpg https://i.stack.imgur.com/1uV3l.jpg
- fengb 7y agoMost compilers for 8-bit and 16-bit CPUs, e.g. Z80 or 80286.
- segfaultbuserr 7y agoMany C compilers that target 8-bit (sometimes 16-bit) machines. MOS 6502, Zilog Z80, and Motorola 6809. Modern examples include Intel 8051, AVR and PIC.
- caf 7y agoTurbo C on MS-DOS for one. In fact 16-bit int was the norm on that platform, because the architecture didn't have 32-bit general purpose registers. In the C89 days, you'd use 'short' in aggregates (structs and array) for values you knew wouldn't exceed 16 bits so didn't want to potentially waste space; 'long' in situations where you knew 16 bits wouldn't be enough; and 'int' the rest of the time (where 16 bits was enough, and there weren't any storage benefits to outweigh the performance benefit of using the native word size).
- rcfox 7y agoMy first thought was MSDOS/Turbo C, and I found this page when looking for confirmation: http://synfare.com/599N105E/hwdocs/sizes.html http://synfare.com/599N105E/hwdocs/sizes.html
- sys_64738 7y agoI emailed this to my boss telling him I got 0/5. He just setup a 1:1 meeting first thing Monday AM.
- Something1234 7y agoLet us know how it goes...
- floki999 7y ago1/5. I don’t know C.
- bandushrew 7y ago4/5 I tricked myself into thinking I could figure out the last one....oops.
- flowerlad 7y ago“I don’t know” is not the right answer. I do know. I know the answer to be “Unspecified”.
- scarcelycoher 7y agoBy that logic, someone who says "the origin of handedness is unknown" contradicts himself, since he does know the origin of handedness to be "unknown".
- thayne 7y agoBut you _don't_ know what it returns, because the behavior is either undefined or implementation defined, and you don't know the implementation.
- ben509 7y agoBut you do know that it's undefined or implementation defined. It's a "known unknown".
- pksadiq 7y agoThere are a few problems with the questionnaire. "I don't know" is pretty generic choice to be given/choosen. Say for example, in question 5, the statement "return i++ + ++i;" is undefined, because the value of i is read and modified twice in a single sequence point (and of course, the order of addition is unspecified), which is not allowed in C. So the answer is "Undefined." (The explanation given in the page not accurate enough in terms of C) And for question 1, the code is valid, but the result is not strictly defined. It depends on the implementation. So the answer is "Implementation defined." The usage of "main()" hurts me, the strictly conforming way is to write it as "int main(void)" (or similar) I feel like the questionnaire piss off people who really knows C.
- Dylan16807 7y ago> So the answer is "Undefined." The code is undefined, but "I don't know." is still the correct answer for what happens to the variable.
- pksadiq 7y ago> The code is undefined, but "I don't know." is still the correct answer for what happens to the variable. Well, then a better choice would be "I can't know."
- deleted 7y ago[deleted]
- caf 7y agoThere is a minor error in the explanation for the third one: the minimum allowed value for CHAR_BIT in C is 8 (it does not affect the result, principally because the value of ' ' could be anything in the range of char).
- jepler 7y agoThat's the one where I wanted most to quibble with the "explanation" of why there is no set answer: To me, the top of the line answer is that the value of the string constant ' ' as an integer is implementation-defined (or maybe it depends on the execution environment? See, I'll get the precise wording wong too); anyway, space is 32 in ASCII but 64 in EBCDIC. The most you could say is that it's not zero (and maybe that it's not -1? I'd have to check how EOF is defined)..
- Tharre 7y ago5/5, but I don't think this test is very good at capturing the more obscure features of C, they all just deal with the fact that platforms have different datatypes/alignment requirements, except for the last one. I think a better example would be the following: int a=1, b=2, i, j; i = a += 2, a + b; j = (a += 2, a + b); Whats the value of a, b, i, j? Hint: i and j are different. Which begs the question, why does C have those features in the first place? The only C code where it's reasonably common seems to be in crypto algorithms.
- umanwizard 7y ago5 and 7? If I remember the behavior of the comma operator correctly. Anyway, I am inclined to agree that these are misfeatures. I’d almost certainly ask for it to be changed in code review.
- kristopolous 7y agoThis is a perfect example of what I hate about some tests. Didn't quite know the purpose of the test, there's a difference between code for any machine and any compiler and gcc running on some vanilla x86, which is pretty common, and could have been the content (ex: you say it's undefined, that's obvious, everyone knows that already, but it's still deterministic... Here's a breakdown of what happens in practice, blah blah blah). There's a real difference between the kind of "knowing" here and say the kind of "knowing" with unallocated pointers. If it said "esoteric implementation on exotic hardware" then it's easy, you know what they are trying to do. If it said C89 you also know what's up. But how it's presented, it's a guess. This was endemic throughout schooling. Instructors would say "just do your best" and I'd be like "wtf? There's like 2,3, maybe 4 perspectives on this with different answers depending on how clever you're trying to be or what you're trying to get at... Might as well put "I'm thinking of a number 1 through 5" on the exam".
- seba_dos1 7y agoYou can easily get bitten by at least one of those examples just by compiling your application written on x86 to ARM to get it running on Android, so not sure if it's as esoteric as you think.
- FartyMcFarter 7y agoOr on different compilers, or the same compiler with different options, etc.
- Nullabillity 7y agoOr a new release of the same compiler.
- deleted 7y ago[deleted]
- TazeTSchnitzel 7y agoBut the test doesn't ask about C as compiled by X compiler on Y architecture. It just asks about C. (You also seem to be assuming GCC is more predictable about undefined behaviour than it actually is.)
- nanoanon 7y agoFunny. My first thought of question one is we'd need to make assumptions about which architecture we're working on to know this answer. By the time I got to question 3, I realized the author's trend. This is both the curse and blessing of C, a language that gives you just barely a high level translation layer over the raw silicon.
- deleted 7y ago[deleted]
- seba_dos1 7y ago4/5, forgot that integer promotion is more complicated than what intuition would tell you. To be honest if was pretty obvious what the right answer was, but tried to answer honestly anyway ;)
- ummonk 7y agoYeah I assumed short would be at least as big as a char and would this be comparing size of short against short. Didn’t realize it would get promoted to int.
- ioquatix 7y agoOn a typical modern arch, there are consistent and reasonable answers: 1. 8 (https://godbolt.org/z/Udcuj0 https://godbolt.org/z/Udcuj0) 2. 0 (https://godbolt.org/z/kZz1YQ https://godbolt.org/z/kZz1YQ) 3. -96 (https://godbolt.org/z/1Xq_Oo https://godbolt.org/z/1Xq_Oo) 4. 1 (https://godbolt.org/z/MIo0s_ https://godbolt.org/z/MIo0s_) 5. 2 (https://godbolt.org/z/J0dsVW https://godbolt.org/z/J0dsVW) I agree, you can argue that it's unspecified, undefined, or whatever. It might not be well defined by the C specification, but none of these programs produce surprising output. Programming in the real world requires that you are able to read and write code like this, even if it requires that you investigate (and depend) the specific behaviour of your compiler/platform.
- 3JPLW 7y ago> produce well defined output. Perhaps “produce consistent results” would be more appropriate.
- seba_dos1 7y agoSwitch the compiler to ARM, which is as "typical modern arch" as it gets, and see for yourself.
- ioquatix 7y agoI don't think it's surprising when you switch machine architecture and/or word sizes that you get different results. In fact for me, that's completely normal and to be expected.
- dang 7y agoDiscussed at the time: https://news.ycombinator.com/item?id=12902304 https://news.ycombinator.com/item?id=12902304 https://news.ycombinator.com/item?id=12900279 https://news.ycombinator.com/item?id=12900279 Similarly titled in 2012: https://news.ycombinator.com/item?id=4657317 https://news.ycombinator.com/item?id=4657317 and 2011: https://news.ycombinator.com/item?id=3125891 https://news.ycombinator.com/item?id=3125891
- dmcdm 7y agoI found it an amusing excrcise, if not terribly relevant, even as someone who spends 90% of his dev time in C. What rubs me about these sorts of articles is they make some presumption about the importance and nessecisity of writing truely portable C, as if the "C Standard" were in and of itself a terribly useful tool. This is in contrast to where I live most of the time which is "GCC as an assembler macro language" (for a popular exposition on this subject see https://raphlinus.github.io/programming/rust/2018/08/17/undefined-behavior.html https://raphlinus.github.io/programming/rust/2018/08/17/unde...). And yeah, reading through the problem set I was critiquing it in context of my shop's standards, where we might be packing and padding, using cacheline alignment, static assertions about sizeof things, specific integer types, etc. So these sorts of articles just come off as a little pendantic to folks like me. I don't doubt they're useful for some folks, and I guess it's interesting to come up from the depths of non-standard GNU extensions and march= flags to see what I take for granted.
- deleted 7y ago[deleted]
- FartyMcFarter 7y agoGCC and many other compilers have been known to change the consequences of undefined behavior unpredictably when upgrading, changing compiler flags, etc. For some examples that matters.
- stefan_ 7y agoWhere the author goes wrong is in assuming that somehow "I don't know" can be a final answer to these things. No, it is absolutely fucking vital that you know how the compiler will pad your structures in C. Similarly to the "what size is an int" on your architecture - on an ATmega8 this is 16 bit, but the chip can't actually do all 16 bit operations in single instructions.
- lvturner 7y agoI took that to be the point of the article though, that just looking at the code wasn't enough to know and you needed to go further to answer these cases for your exact use case or target platform.
- deleted 7y ago[deleted]
- microcolonel 7y agoIn practice, things in C are not as undefined as the ISO working group specifies them. It is virtually inconceivable that a mainstream compiler stack would do anything other than what you'd expect with example four. As for struct alignment, that's something that most C programmers should know is implementation-defined (which is one of the reasons we even have sizeof to begin with, apart from the mere convenience of it). Sure, you've made your point, but you've made it in a ham-fisted way which doesn't really help people understand why a given undefined or implementation-defined behaviour is the way it is, and what things they should verify about the implementation in order to predict where their code will not work.
- FartyMcFarter 7y ago> It is virtually inconceivable that a mainstream compiler stack would do anything other than what you'd expect with example four. I disagree. I can easily conceive of a (compiler, architecture, compiler options) tuple that simply crashes with an error at compile time or runtime with that code. Namely, some compiler for a 16-bit architecture with "sanitization" options enabled and optimizations disabled. Integer overflow is one of the easiest "undefined behavior" cases to identify with mechanical checks. Much easier than bounds checking for example, where a general solution is quite tricky.
- microcolonel 7y agoSure, but portable C programs are not written for systems with 16-bit machine words practically ever anymore. Nobody's expecting to run libopus 1.3.1 unmodified on an 8051 (even if it might well do, it probably uses stdint.h anyway!). Furthermore, I've used toolchains for machines with 16-bit machine words, which made int 32 bits; surely this isn't uncommon.
- ghettoimp 7y agoI think this objection boils down to your perspective on what we mean by "C". It's reasonable for some folks (especially working programmers who need to "get stuff done") to think that "what a reasonable compiler in their problem domain" would do is what "C" means. It's equally reasonable for other folks (especially compiler writers, verification experts, researchers, etc.) to think the ISO standard is what "C" means. It would be great for the standard to be more "reasonable" and have less undefined behavior. But I, for one, cannot think of a more horrible, thankless chore than actually trying to make that happen. So much code is written in "C", and there are so many compilers and platforms, modern and legacy, that "C" runs on, each with their own notion of "reasonable," that it will take an incredible amount of work.
- chadcmulligan 7y agoIsn't there a more fundamental flaw in these questions? main() always returns an int, whether that's 4 or 8 bytes, 0 or 1 means success or failure depends on the implementation. here's a bit of a discussion https://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c https://stackoverflow.com/questions/204476/what-should-main-... Reminds me of the dumb exams some teachers would set to trick you when in school to make themselves feel superior.
- TazeTSchnitzel 7y agoWhat's wrong with it returning int here? They aren't using any variables bigger int, and the meaning of return codes is irrelevant.
- saagarjha 7y agoOmitting the return type for main is legal in C89.
- _kst_ 7y agoI submitted a GitHub issue for the `main()` definitions and some other quibbles. https://github.com/akalenuk/wordsandbuttons/issues/12 https://github.com/akalenuk/wordsandbuttons/issues/12
- _kst_ 7y agoIt's been corrected in the repo, but as I write this the web page has not been updated.
- ummonk 7y agoI got #2 wrong, and definitely should have known about integer promotion.
- jtl999 7y agoI knew there was something up because long ago when developing for Arduino boards as part of a course, my mentor educated me on the difference of size of datatypes across different architectures.
- zw123456 7y agoThe better wording would be D) not enough information to give a definitive answer. It's like the old gotchya question; what is 1+1 ? of course the answer is it depends on if you are using binary or a base of integer >2.
- zw123456 7y agoIt is not difficult to overcome these limitations of C by typedef definitive types like signed int32, unsigned int8 and so on. Many embedded C .h have that as a standard way of clearing things up. of course you can always sizeof(int) or whatever. (BTW this quiz or one like has been around a long time, but still a good reminder).
- marksmith2996 7y agoThe real answer is, all 5 questions don't compile so they don't return anything.
- saagarjha 7y agoWhat compiler are you using?
- dingo_bat 7y agoI feel like the test is inaccurate. Each of those snippets has an output that can be repeated by anybody using gcc on x86. So unless you are on some exotic hardware, none of the answers is "I don't know". And if you are using a power pc or something then you should specify that.
- kahlonel 7y agoPro tip: avoid `int`s as much as possible in your C code. Use <stdint.h> defined macros instead.
- saagarjha 7y agoThere is a time and place for int32_t.
- AdieuToLogic 7y ago> There is a time and place for int32_t. And time_t[0] is not one. ;-) 0 - https://pubs.opengroup.org/onlinepubs/9699919799/functions/time.html https://pubs.opengroup.org/onlinepubs/9699919799/functions/t...
- AdieuToLogic 7y agoI guess that joke was hard to C.
- morpheuskafka 7y agoIf we're going to be --pedantic, shouldn't the author specify the exact standard of the C language under test? A lot of companies have varying implementations of C and perhaps some do specify some of the behavior at hand here.
- saagarjha 7y agoImplementations of C≠C standards, though of course I'm sure some random obscure compiler has tried to call their C dialect a "standard" at some point.
- FpUser 7y agoIt is an unsavory set of questions that has no bearing on practical work, also implementation dependent. The answer is: No, I do not know C or any other language for that matter. I know some implementations of various languages just enough to write sound and readable code. And as I forced to use a bit more languages than I like I rely on local/Internet search to keep my brains concentrated on accomplishing the actual task rather then effing them up trying to figure out some esoteric constructs.
- soup10 7y agoi didn't do the quiz, but just looking at the first question I have run across structure packing/padding issues so its not entirely useless
- minitech 7y agoOf course it has a bearing on practical work, and that it’s implementation-dependent is the whole point. These are mistaken assumptions people make in the real world.
- rayiner 7y agoThe questions are a bit cute, but they’re not testing obscure corner cases of the language. It’s not like asking if you have the trigraphs memorized. It’s testing fundamental rules about how C works: overflow, integer promotion, order of operations, memory layout, etc.
- viraptor 7y agoThey're all obscure in a "I wouldn't write code like that or let it go through review" sense. They're very synthetic cases.
- rayiner 7y agoBut would you write code that adds integers of two different types?Then you need to know the integer promotion rules. And this is just us just a way of testing that.
- emmelaich 7y agoDon't we need to know the sizeof int and void* on this machine? [edit - that seems to be the point sigh]
- ridiculous_fish 7y agoUB nasal demons etc etc. But often we encounter UB in code that's already shipped. So it's good to have an intuition about what machine code was actually emitted, for example when deciding if a crash report is due to this particular UB, or not.
- saagarjha 7y agoOr you could just look at the binary you shipped: by the time it’s compiled, you don’t really have to deal with undefined behavior.
- graycat 7y agoj = 1 k = 2 i = ++j+++++k++ i = ? j = ? k = ?
- pflanze 7y agoWhat are the best strategies to cope with the undefined areas in C?
- saagarjha 7y agoThe best one is to not write C. The second best is probably to read the standard papers, be very careful (perhaps using a secure style guideline) and making generous use of tooling to help you catch mistakes.
- mhh__ 7y agoEither don't use C, or use C and avoid UB with Sanitizers and skill (i.e. using a typedef'd that you guarantee that the size of x is ...)
- WC3w6pXxgGd 7y agoNo.
- beached_whale 7y agoThe third one has another implementation defined aspect. We do not know the value of a space ' ', in ascii it is 0x20(32) but that depends on the system, in EBCDIC it is 0x40(64).
- deleted 7y ago[deleted]
- deleted 7y ago[deleted]
- zoomablemind 7y ago> Eventually, I had to learn to rely on the standard instead of folklore; to trust measurements and not presumptions... Indeed, testing your assumptions, because even a defined standard may result in a differing implementation of it. Especially in critical applications, testing the expectations gives some sense of a defined behavior. This quizz is amusing as a mental exercise and a parable, but in reality all of these cases had to be fleshed out on a real platform, with real compiler and ... specified expectations of the behavior. None of the cases in fact communicate a clear intent, except maybe #1 to figure out the padded size, still it's somewhat open-ended. Perhaps returning a specific condition (return sizeof(struct ...)==5; ) would show a clear intent. Not that it would change the right answer, just such a case may indeed be true on a specific platform, compile flags erc.
- zoomablemind 7y agoJust to flesh this out, I put the puzzle code through gcc 6.3, on ideone https://ideone.com/PziSzq https://ideone.com/PziSzq Result: 1:8 2:0 3:-96 4:1 5:2 Sure, there's a bunch of warnings emitted... fortunately.
- deleted 7y ago[deleted]
- WalterBright 7y agoHaving written a conforming C compiler, at one point I knew everything there was to know about C (I forget details now and then, or confusing them with C++ and D). But knowing every engineering detail is not the same thing as knowing how to program in C effectively. It's like being the engineer who designs a Grand Prix car. It does not mean you can drive it faster around the track than anyone else. Not even close. For example, the C preprocessor is surprisingly complicated. I had to scrap it and rewrite it completely 3 times. If you try to make use of all those oddities, my advice is don't waste your time. Over time I removed all the C preprocessor tricks from my own code and just wrote ordinary C in its place. Much better.
- rofo1 7y agoStrong agreement here. You can limit yourself by choice to certain areas of the language that you know inside out (you know the asm they produce, etc.) and use it to solve problems. Don't worry about every single corner case. As you said, you can easily forget those things, especially if it's not your day-to-day job. The same idea and principle can be found in "JavaScript - The Good Parts".
- mhh__ 7y agoHaving recently been doing some web development, I'd argue that JavaScript's design (even today, despite some modern additions) is so conducive to undebuggable spaghetti code (i.e. this ) that there really are no good parts. Sometimes the technology is objectively the wrong choice i.e. compiling javascript to native code (Not a JIT).
- WalterBright 7y agoSome languages do fight your attempts to write good code every step of the way :-) No, I won't name names.
- mhh__ 7y agoI'm currently writing a library that loads, parses and includes c headers at compile time, in D. It's not finished but let's just say I've managed to make yours and Andrei's thoughtful design into a monster
- redbumble 7y agoCan't even make the test. Which version of C? Which platform? Under DOS in the 90's, the answer to the first question would have been 3, it's not even proposed in the options.
- Sharlin 7y agoEach of the questions has exactly one answer that is correct regardless of version and platform.
- throwaway5153 7y agoMy answer to a lot of these questions is "If you write code like this and check it in to our corporate repository, I will cut out your heart and make you eat it."
- rok0897 7y agorohit
- mhh__ 7y agoThis is the language we still choose to trust our credit cards with.
- rramadass 7y agoI hope you were joking. This is just a "gotcha" quiz and not relevant at all.
- mhh__ 7y agoI'm almost not. I made the point because this level of ambiguity and "do it yourself" is consistent throughout the language. I know why we still use C, but the use of C is inherently prone to security problems. C does not provide bounds checking by default, so it can be forgotten (Heartbleed) and the lack of either static checking, RAII or garbage collection (Not as a library e.g. Boehm) makes memory corruption all but inevitable.
- rramadass 7y agoPeople are forgetting that it is the very "looseness" of C that is responsible for its great success. The sheer volume of code in C (specifically, any number of complex and critical software) is a testament to that. People keep parroting the same old tired tropes about C without reflection and thought. All the problems, both real and imaginary, in the language have been worked through/around since the beginning by simple discipline, guidelines and external libraries. I am always annoyed when people bring up "memory corruption" as if it were some primordial sin. The power to manipulate raw memory in whatever way i want is so crucial that i am willing to live with the downside of possible corruption. In fact most of the people i have worked with and myself never found this to be so much of a problem as everybody else makes it out to be. We always followed good guidelines, had special libraries for memory allocation as needed and testing procedures to catch memory leaks. Everything worked out fine. In conclusion, the power given to Programmers by C far outweighs any of its perceived downsides in real-world scenarios.
- mhh__ 7y ago
- kabes 7y agoI don't know any c, so I answered "I don't know" on all the questions. Turns out I'm actually a C genius.
- kuroguro 7y agoAgh, 0/5! They were correct in the context of MSVC tho.
- satyenr 7y agoWhat a lot of people don’t get is that it’s not pointers or manual memory management or even lack of language level support for “modern features” like object oriented programming, exceptions etc. that make C a pain to use. No it is the undefined and implementation dependent behaviours. There are simply so many of them that even experienced C programmers may, at times, run into trouble. C is essentially a portable assembler. It’s not enough to learn the language, you need to have deep understanding of the underlying hardware and compiler infrastructure.
- mpweiher 7y agoWhile I got my 5/5, I think the answers should have been “I seriously don’t want to know”.
- e1ghtSpace 7y agoMy friend doesn't know how to code and got the whole questionnaire correct.
- rramadass 7y agoThis quiz wasn't illuminating at all. You generally start with assuming and validating a "C Datatype Model" i.e. ILP32/LP64 etc. for your system. Once you know that, these questions are easily answered. If you want to see some real tricky C code, see some of the articles here: https://locklessinc.com/articles/ https://locklessinc.com/articles/
- professorTuring 7y agoIt is curious because, in each of the questions I encountered problems with the own questionnaire and I tended to answer in the way the writer thought. And then you find "it's a trap". I think the questionnaire is not honest enought, a better answer for D should have been: "we need more information" or "there are programming inconsistences"... I thought that when selecting "I don't know" I was telling "I don't know what's happening with the code and the inner datails".
- cat_plus_plus 7y agoWell, that's a copout. Of course, if you take absolutely any computer architecture, you can't assume simple things like sizeof(int) or data structure alignment. But if sizeof(int) is at 4 and data needs to be aligned by its own size - like on any real architecture relevant today - many of these questions have a deterministic answer. In practice, compiler bugs are a much bigger issue than architecture assumptions.
- tillulen 7y agoWhat’s the latest compiler bug that caused a serious issue for you? (Genuinely interested, no sarcasm here.)
- layoutIfNeeded 7y agoBy the third question it was obvious that all of them are implementation-dependent or undefined behaviour.
- baalimago 7y agoThis must be the first time my lack of knowledge gave me full score.
- heinrichhartman 7y agoThere is a difference between "I don't know" and "undefined behaviour". I know that most of this stuff is undefined according to the spec. But I (might) also know what my particular GCC version does in these cases. What I know for sure, that those programs do output something, and it's not "I don't know" (the string) ; ) What I don't know, is what level of sophistication the author assumes.
- Ultimatt 7y agoReplacing "I don't know" with "this is undefined in the spec" or "this is implementation specific" would probably increase the pass rates.
- m_kim 7y agoBut a code based on several standards, not only on C standard. For example we know, that basic source character sets should contain space (C11 5.2.1), we know that character constants has type "int" and that character constants represent value equal to the code of a symbol (C11 5.4.4). We know used source character set and we know code of the space character. We can configure specific source character set on the POSIX compatible systems. We know that return statement in the main function equivalent to the call to exit function (C11 5.1.2.2.3), we know that only 8 least significant bits will be used from returned value (POSIX.1-2001 definition of "exit"), we know that INT_MAX should be at least 32767 (C11 5.2.4.2.1) so we sure that the result that we got from "return" statement in the "main" function is positive integer from 0 to 512. Finally if we configure source character set to be sure that ' ' has code 32 we know for sure that we got value 416 in the specified example. So we know for sure answer on question 3 based on the C11, POSIX.1-2017, and ISO 646 standards.
- NieDzejkob 7y agoI don't know if POSIX specifies CHAR_MAX, but on most systems, storing the value into a char will change the value, making it everything but 416: https://tio.run/##S0oszvifnFiiYFeSWlyil6xgY@Pq7/Y/M69EITcxM0@jLD8zRVOhmktBITkjsUghUcFWQR0ItRQMja2BgkWpJaVFeQqJ1ly1/4H6uLjSk5MVICZx6ekn6uWXlnClJmfkK6jY/wcA https://tio.run/##S0oszvifnFiiYFeSWlyil6xgY@Pq7/Y/M69EITcxM0...
- deleted 7y ago[deleted]
- deleted 7y ago[deleted]
- m_kim 7y agoMy mistake: We have (32*13) with minimal possible CHAR_BIT is 8. So it either 416 for char bigger then eight bits, or 160 for unsigned eight bits char, or -96 for signed eight bits char. Then it extended to the signed integer value (one of this three values), and then we got result as (int)(status & 0377). For all three cases result will be 160.
- nappy-doo 7y agoThe author's explanations of the first three answers aren't sufficient. There is no requirement within C for `int` and `char` to be different sizes. Similarly, you don't know what the resolution of ' '*13 will be. It's architecture dependent. C, for all it's simplicity, is a relatively complex language.
- squarefoot 7y agoI scored 2, but mostly out of luck for being 100% sure only about the 1st question, as I encountered alignment problems a lot of times in the past when dealing with structures to be sent through the network, and also between different architectures (and sometimes endianess too). If memory serves, there are #pragma directives to force the compiler to align structure members to a given interval, but they're compiler dependent and would make a non portable piece of code even less portable.
- GorgeRonde 7y agoWent to an IRC chat room when I was learning C in school. Asked if you could return a pointer to something that lives on the stack. Was talked down by an all-knowing dude telling me to go read K&R again. Proceeded to write a code sample [1] that showed it is possible (it's not really stable but works reliably in recursive calls IIRC). I do not like this attitude (then again it was just one random dude). [1] https://www.onlinegdb.com/HyO5VXRxS https://www.onlinegdb.com/HyO5VXRxS
- dahart 7y ago> it is possible (it’s not really stable but works reliably in recursive calls IIRC). [...] I do not like this attitude You might want to listen. You’re getting the K&R comment and the downvotes because this does not work, ever. It’s a really, really bad idea. In recursive calls, it might not crash right away, but you will have bad data, the memory at the pointer address will have been overwritten by the next stack frame that’s placed there. Don’t ever return pointers to local memory because the memory is “gone” and unsafe to use the moment your function returns. Even if you try it and think it works, it can and probably will crash or run incorrectly in any other scenario - different person, different computer, different compiler, different day... Your comments about getting a warning and ‘However if you wrap the local’s address... it “works”’ should be clues. The warning is the compiler telling you not to do it. The workaround doesn’t work, it only compiles. By using aliasing, you’re only tricking the compiler into not warning you, but the warning is there for a reason.
- todd8 7y agoYes. Signal handlers allow C programs to respond to events outside of the normal control flow (see signal.h, etc.). This means that once a function, say fnc1, has returned, the memory on the stack that was used by fnc1 can end up being reused at any point in time. A signal, perhaps generated completely asynchronous to the program itself by a different process, causes a stack frame to be allocated (possibly on top of fnc1’s old stack frame) for use by the corresponding signal handler. This could happen at any time, even before fnc1’s caller gets a chance to use the pointer returned by fnc1.
- zzo38computer 7y agoI managed to answer all of the questions correctly; I recognized them as undefined. Still, there may be enough definition on the set of computers the program will run on, to do, in some cases (for example, that char is at least 8-bits, and/or that it is ASCII). But the thing that would be better to do, in my opinion, may be like having LLVM with macros (including standard macros for dealing with differences of systems, and user-defined macros for your own use).
- strenholme 7y agoThe one that got me is this: uint32_t foo = 1; foo <<= 32; Here, I figured that foo would always be 0. Wrong. It was always 0 with GCC, but this is undefined in the spec and code like this can have a different value in clang. I actually had to make a security update to my little open source project because of this (although the code I wrote did not manifest the bug in an insecure way, even with clang).
- childintime 7y agoI posted this in the embedded C-shop I work, under the comment that exactly in this place all should pass this test. Sadly only 1 in 5 passed the test (yours truly). Admittedly, this test was binary: either you pass or fail all of the questions (which is also sort of a give-away). In the end this test proved to be a really valuable, because the "I don't know" drove the point home, specially for smart folks who don't like to answer any test, ever, with "I don't know".
- FraKtus 7y agoAt least for the third question (char a = ' ' * 13;) XCode warns "Implicit conversion from 'int' to 'char' changes value from 416 to -96". And for the fifth (return i++ + ++i;) it warns "Multiple unsequenced modifications to 'i'". I would not skip those warnings.
- raviolo 7y agoCould someone explain why in question 5 i = 0; return i++ + ++i; Could produce different results?
- detaro 7y agoThere's explanations at the bottom after you click the button.
- raviolo 7y agoI read it but I still don’t understand. Isn’t it 0 + 2 vs 1 + 1? How would it produce something other than 2?
- JKCalhoun 7y agoHow do you get 0 + 2? I could imagine the post-increment happening after the sum: giving 0 + 1…
- dahart 7y agoThat’s what I imagined, and what I get with Cygwin gcc, the result is 1. I thought that the post-increment was supposed to always only happen after the “statement”, but I was wrong. Other compilers, like gcc on Ubuntu return 2. This looks like a good explanation of why both are correct and why it’s confusing: https://stackoverflow.com/a/4445841 https://stackoverflow.com/a/4445841
- raviolo 7y agoSo for the left-to-right operand evaluation order I thought it’s this: look at the left operand, take zero. Then post-increment, now it’s one. Move on to the right operand. Pre-increment what is 1, so now it’s 2. Take 2. So it 0 + 2?
- Dylan16807 7y agoImagine a dumb piece of hardware storing your variables. Two pieces of a statement try to do conflicting things to the same variable at the same time. This can cause the data to get corrupted, or the entire chip to have a fault. The C standard allows an implementation like this.
- GnarfGnarf 7y agoI took it as "What will this do on your compiler?"
- dahart 7y ago> And at this point, I only have to apologize. The test is clearly provocative and may even be a little offensive. I’m sorry if it causes any aggravation. [...] It was a research project in nuclear power plant automation, where absolutely no underspecification was tolerable. I appreciate the apology here, and I can totally understand the concern about the spec in a safety critical environment. Still, all questions on this test except the first are clearly examples of things you should never ever do in production code, which might undermine the message a bit? Yes, you can write bad code, and that’s true in every language I’ve ever used. I’m guessing it would be hard to find a modern compiler on Windows, Mac or Linux that produced padding other than rounding up to nearest 4 bytes? Sizeof(a+b) is obviously a weird thing to do. char a = ‘ ‘ * 13 produces an overflow warning in gcc. (((((i >= i) << i) >> i) <= i)) I hope nobody really did that. return i++ + ++i; Not doing exactly this was drilled into us in CS 101. Still, I’d be interested to hear about a compiler that doesn’t return 1, since many people rely on the fact that ++i is pre-increment and i++ is post-increment. I don’t doubt one is out there, I’m curious to know which. There probably weren’t much better choices 20 years ago... what would be the best choices today for a branch new nuclear power plant?
- noahmorrison 7y agoStill, I’d be interested to hear about a compiler that doesn’t return 1 gcc (Ubuntu 8.3.0-6ubuntu1~18.10.1) 8.3.0 returns 2 (executes from left to right... at least the first time I ran it).
- dahart 7y agoWow, you’re right. Me too on ubu 16. Okay, I guess it’s not about pre or post increment. Maybe I should read the spec... ;) And good reason not to do this in code!