4 ms·
This article highlights yet more "gotcha" optimizations that, IMHO, do more harm than good. There is no reason that any compiler must miscompile &x->y, where x
by quotemstr 12y ago
This article highlights yet more "gotcha" optimizations that, IMHO, do more harm than good. There is no reason that any compiler must miscompile &x->y, where x == NULL. What's undefined in C can be well-defined in POSIX or in the documentation of a specific build environment. It would behoove higher-level standards to make this construct well-defined even if C itself doesn't.
- wyldfire 12y agoI think POSIX almost always specifies strict additions in the form of function declarations and expected behavior of those functions, and some generic system-wide features. Your suggested change would amount to a delta on the language spec. That would probably be unprecedented.
- TheLoneWolfling 12y agoDefining undefined behavior doesn't change the language spec, only adds to it. All it's doing is saying that "my compiler uses the freedom to do anything that undefined behavior grants to do something sane". By definition, anything that would be broken by such a change was already undefined behavior.
- Retra 12y agoThat's a reasonable way to do things, but only if it is not a misappropriation of resources and effort. If someone is writing C code, it is generally inadvisable to rely on behavior that is implementation specific, even if your implementation does nice things. That would violate portability and readability, both things that are nearly unanimously considered to be ideals of programming practice. So really, the "something sane" that you are talking about should be issuing an error or warning.
- TheLoneWolfling 12y agoI don't see the difference between saying "this is valid C99 code" and "this is valid 'paranoid C' code". At least not if your 'paranoid C' compiler is working to a specification.
- lmm 12y agoPeople would compile "paranoid C" with a normal C compiler (perhaps there is no paranoid C compiler for their platform). If your code is silently broken on some compilers, that's arguably even worse than being silently broken on all compilers. It would be better to a) make a compiler that errors out on any undefined behaviour (so that people would fix it in their code and it would then be fixed everywhere they compile) and/or b) use a new language.
- TheLoneWolfling 12y ago"Paranoid C" would be a new language. It's just far easier to define a new language in terms of an extension to an existing language than making a new one from scratch. No need to throw the baby out with the bathwater. I mean, C++ started as an extension to C in the same way. The reasoning for having it an extension is mainly so that current code can be trivially ported.
- lmm 12y agoIf you permit calling C libraries from "paranoid C", that would give a very confusing debugging experience, where the semantics of identical code was different depending on which file that code happened to reside in. If you don't... maybe. But do you realistically think "paranoid C" would ever get its library ecosystem up to a level where it matched e.g. OCaml? Do you think embedded vendors would be more likely to support it (the other big use case for C)? If you're going to be switching libraries anyway, OCaml is a much nicer language to work in.
- TheLoneWolfling 12y agoYou can say the same about C and C++: [1] (On a side note. I like OCaml, but don't like the syntax. I wish there was a language out there that was basically OCaml with c-like syntax. Or rather, I wish language syntax in general was less coupled with language semantics. It should be possible, and is, to, for example, automatically convert between Pythonic-style indentation and C-style braces and lisp-esque braces. Define the language in terms of an AST and leave the syntax up to the editor.) [1] http://stackoverflow.com/questions/12887700/can-code-that-is-valid-in-both-c-and-c-produce-different-behavior-when-compile http://stackoverflow.com/questions/12887700/can-code-that-is...
- TheLoneWolfling 12y agoAlso, I'd argue that half the time trying to write things in a portable manner in C is drastically less readable. Look at the madness that ensues when you try to do something as simple as a bitwise rotation, for instance.
- pcwalton 12y agoBeing able to assume that a pointer is not null opens up some really interesting optimizations. For example, if you know that a pointer is dereferenceable, then you can speculatively hoist loads of it out of a loop as long as there are no possibly-aliasable pointer stores in between. That's why it's helpful for C compilers to be able to aggressively infer that pointers are not null.
- ufo 12y agoJust wondering: how much do these particular optimizations end up being worth in the end? Is it something noticeable or is it like array bounds checking where its almost always OK to leave the checks in the end?
- joosters 12y agoIt's impossible to give a general answer. You could have a tight loop in a performance critical part of your code, where optimising out the NULL check removes (say) 25% of the loop code. Or, the check might be negligible. It depends upon the code. That's why IMO people saying that the compiler shouldn't bother with these 'excessive' optimisations are wrong. It might be worthless for them and their programs, but might be valuable for others. Don't force your priorities upon other people.
- pcwalton 12y agoYes. I'd also add that loop optimizations tend to magnify in importance when you consider that the loop might be vectorized. Especially since the state of scatter/gather SIMD intrinsics is so poor at the moment...
- jwatte 12y agoThis is entirely wrong. Taking the address of a field doesn't evaluate the field, and any compiler that does a load for that is broken.
- pcwalton 12y ago
- dannnn 12y agoIt's not necessarily a "miscompile". C is supposed to be portable to even completely stupid architectures, and on some architectures, just loading an invalid pointer value into a register will cause a trap, even if you don't dereference it. So on those machines, if x is NULL, then an unoptimized compile of ((size_t)(&x->y)) will result in code that crashes. So that's why it's undefined. (I'm pretty sure POSIX does impose certain non-stupidity requirements on its underlying architecture, so there are things that are undefined in plain C that are guaranteed to work on any POSIX platform. But I don't know if this is one of them.)
- deleted 12y ago[deleted]