5 ms·
It always works as you expect? Really? C is one of the few languages, along with C++, that revels in undefined behaviour. It can be very hard to reliably know
by zigzigzag 10y ago
It always works as you expect? Really?
C is one of the few languages, along with C++, that revels in undefined behaviour. It can be very hard to reliably know what a C program will do if it's not written very carefully because there are so many constructs that look benign but which are technically wrong, and the compiler will mercilessly exploit in order to optimise your program into nonsense.
- deagler 10y agoThis, While C and C++ are both very powerful languages and could still be considered the "industry standard"(loosely used) It is definitely not a language that will make your applications work as expected, I would say that C#/Java or higher level scripting languages like Lua or Javascript are languages that will let you make "code it and it works" applications
- MaulingMonkey 10y agoC and C++ are the only languages I regularly use wherein I need to resort to disassembly to debug the damn thing.
- retro64 10y agoI find this statement hard to imagine. I've been coding professionally in C++ for just shy of 20 years now (and in C for a few years before that) and have only resorted to assembly when I needed to actually use assembly for performance reasons. Actually - not completely true. I do like to look at the assembly from time to time for other reasons, but this is rare.
- MaulingMonkey 10y agoEven when I have performance to worry about, intrinsics are usually an option - possibly even a superior option - when writing performance sensitive code. But here are some of the cases where I resort to looking at program disassembly - I'll note a theme here of debugging optimized code (because who doesn't love heisenbugs): 1) Diagnosing a crash which turned out to be the result of a 1 byte vtable pointer corruption bug in an older codebase, which turned out to be a bad static_cast in relatively removed code (a good case for boost::polymorphic_downcast!). Simply understanding which pointer was bad in the first place required looking at the disassembly - when you can't rely on your debugger's results thanks to optimization. 2) Figuring out the actual values of variables in crashes and crash dumps of optimized builds to properly root cause a bug, when the debugger gets confused - or simply aggressively inlined and reordered everything so aggressively that there's no sensible values to even display (so, most crash dumps.) 3) Noticing when the optimizer has reordered code "unexpectedly", alerting me to the fact that supposedly thread safe code is in fact nowhere nearly remotely safe and is in fact missing many memory barriers (possibly because their portable macros "helpfully" defaulted to a noop on whatever new and previously unrecognized platform I'm porting to.) 4) Noticing when the optimizer has removed or rewritten code in an "incorrect" manner, helping me debug code that would've worked if it hadn't technically invoked undefined behavior, so I can a) fix it, b) attempt to explain to my coworker that, yes, it's really undefined behavior, and yes, it's actually a problem (typically with a combination of citing the standard and linking INVALID WONTFIX-ed "bugs" in some compiler's bug database), c) be reasonably certain I've actually found the real root cause of a bug and fixed it. Now, yes, I'll admit this isn't 100% of my debugging sessions. And perhaps I'm an outlier. My coworkers generally learn that I can (eventually) tackle pretty much any weird bug they might be struggling with and that I'm happy to help. All the porting I've done reopens a whole codebase's worth of wounds - latent undefined behavior that another compiler's optimizer didn't take advantage of. But on the other hand, I've been lucky enough to never encounter a codegen bug in all the compiler and linker bugs I've found. So far. That I know of. And while "rare" by incidence, these are the debugging sessions that can eat weeks at a time for a single bug, when sufficiently nasty and novel.
- tarancato 10y agoUndefined behaviour is not as prevalent in real world code as reading articles from HN might make you think.
- rwmj 10y agoThis is a very naive statement. Sure there are a handful of good companies that enable every single compiler warning, and fix those warnings, and then run the code through Coverity, and fix all those problems too. Almost no one else does. The amount of terrible C in the real world is enormous.
- kbart 10y ago"The amount of terrible C in the real world is enormous." I'm sure you could say that about pretty much any programming language: "The amount of terrible X in the real world is enormous". There are also plenty of clean, nice, safe C code around (and any other language), there's no need to over-generalize ("Almost no one else does").
- netheril96 10y ago> I'm sure you could say that about pretty much any programming language: "The amount of terrible X in the real world is enormous". But the damage is far greater in C. In other languages you won't have arbitrary code execution or privilege escalation just because the programmer is not careful. Nor will there be, in other languages, so many nondeterministic bugs that show up once in a blue moon.
- kbart 10y ago"It always works as you expect? Really?" Well, it works as defined in standards. It's just not every programmer knows what to expect. C is simple, yet powerful language and with powers comes responsibility. It's not like you can throw some libraries/modules/objects (or whatever it is in other, safe languages) together, upload to server and call it a day -- static testing, debugging, unit testing is a vital part of any semi serious C project.
- 0xfeba 10y agoC++ is far more prone to undefined behaviour and even compilation across systems with the STL.
- JoeAltmaier 10y agoI hear this, but I've rarely experienced it. Maybe I unconsciously avoid such cases with long use. I started with assembler, and debug C/C++ with disassembly turned on, so maybe that's why.
- ArkyBeagle 10y agoIt's just really not that hard to avoid undefined behavior. Really. The worst is arguably integer overflow, and that's not even all that challenging.