4 ms·
C is deceptive, though. It encourages a mental model of high-level assembler, but it's an assembler for an abstract machine, not the actual machine; and compile
by barrkel 9y ago
C is deceptive, though. It encourages a mental model of high-level assembler, but it's an assembler for an abstract machine, not the actual machine; and compilers are increasingly making the difference evident.
- akvadrako 9y agoMaybe many people do have incorrect assumptions about C, but I wouldn't say it's deceptive. The abstract nature becomes plain when using an optimising compiler for a while. And they have been the norm for at least 20 years.
- mrec 9y agoOptimizing compilers have been around for yonks, sure, but I think taking aggressive advantage of UB is relatively recent. See e.g. Regehr in 2012 [1] : > The current crop of C and C++ compilers will exploit undefined behaviors to generate efficient code [...], but not consistently or well. It’s time for us to take this seriously. [1] https://blog.regehr.org/archives/761 https://blog.regehr.org/archives/761
- akvadrako 9y agoI see your comment is grey, so I guess people down-voted you and maybe you want to know why. It's because you are wrong. Compiler optimisations have always been relevant; even in the 90's they would omit entire blocks of code or reorder operations for example. I assume now it's more aggressive, because undefined behavior should never be relied upon. That's the point.
- mrec 9y agoI think you're reading me as saying something much stronger than what I actually meant. When we talk about C being "deceptive" we don't need to consider optimizations that respect the as-if rule. (Well, maybe when looking at the C->asm mapping or trying to benchmark, but that's not the level most people are working at.) The trend toward UB-based optimizations seems significant to me because they can and will take a bunch of C code which looks superficially reasonable, and which used to do X as intended, and suddenly (and perfectly legally) make it start doing Y instead. I assumed that's what barrkel was alluding to above. And yes, I'm sure there are old optimizations which will also do that, but basic things like hoisting and reordering and unrolling and dead-code elimination don't fall into that category.
- akvadrako 9y ago> And yes, I'm sure there are old optimizations which will also do that So then it's not new behavior.
- sevensor 9y agoI think the pre- versus post-increment is a great example of this -- Assembly language is unambiguous about when the increment happens. It happens when you hit the increment instruction. The situation in C is almost intentionally confusing. This was done back in the early days of structured programming. I suspect the motivation was to win people over from using gotos for everything, since it allows for variation in how loops and conditionals are executed.
- pkaye 9y agoSome of the processors back then had various pre-increment vs post-decrement addressing modes so there was a performance difference which one you used. To keeps things unambiguous, use the increment operator in a statement by itself.
- sevensor 9y agoInteresting, that sheds some light on the situation! And indeed, I do always use the increment operator by itself. The amount of extra thought it takes to distinguish while(i--) from while(--i) just isn't worth it, when instead I could write for(;i>0;i--) which is very clear about what the last value of i in the loop is.