5 ms·
C might be low level from the perspective of other systems languages, but that is like calling Apollo 11 simple from the perspective of modern spacecraft. C as
by WJW 2y ago
C might be low level from the perspective of other systems languages, but that is like calling Apollo 11 simple from the perspective of modern spacecraft. C as written is not all that close to what actually gets executed.
For a small example, there are many compilers who would absolutely skip incrementing 'a' in the following code:
uint32_t add_and_subtract_1(uint32_t a) {
a += 1;
a -= 1;
return a;
}
Even though that code contains `a += 1;` clear as day, the chances of any incrementing being done are quite small IMO. It gets even worse in bigger functions where out-of-order execution starts being a thing.
- eru 2y ago> It gets even worse in bigger functions where out-of-order execution starts being a thing. In addition, add that your processor isn't actually executing x86 (nor ARM etc) instructions, but interprets/compiles them to something more fundamental. So there's an additional layer of out-of-order instructions and general shenanigans happening. Especially with branch prediction in the mix.
- johnisgood 2y agoWhy would you want it to increment 1 if we decrement 1 from the same variable? That would be a waste of cycles and a good compiler knows how to optimize it out, or what am I misunderstanding here? What do you expect "it" to do and what does it really do? See: https://news.ycombinator.com/item?id=43320495 https://news.ycombinator.com/item?id=43320495
- lifthrasiir 2y agoIt is unlikely as is, but it frequently arises from macro expansions and inlining.
- acdha 2y agoThat’s a contrived example but in a serious program there would often be code in between or some level of indirection (e.g. one of those values is a lookup, a macro express, or the result of another function). Nothing about that is cheating, it just says that even C programmers cannot expect to look at the compiled code and see a direct mapping from their source code. Your ability to reason about what’s actually executing requires you to internalize how the compiler works in addition to your understanding of the underlying hardware and your application.
- johnisgood 2y agoIn what languages can you do that that is not assembly though? The higher level the language is, the "worse" or difficult it gets, perhaps I am not following the thread right.
- acdha 2y agoYes, this is normal for languages. The only pushback here is against the term “portable assembler” being applied to C, where it’s incomplete often enough that many people feel it’s no longer a helpful label. I think it’s also reflecting the maturity and growth of the industry. A turn of the century programmer could relatively easily find areas where dropping down to assembly was useful, but over the subsequent decades that’s become not only uncommon but often actively harmful: your code hand-optimized for a particular processor is likely slower on newer processors than what a modern compiler emits and is definitely a barrier to portability in an era where not only are ARM and potentially RISC-V of interest but also where code is being run on SIMD units or GPUs. This makes the low-level “portable assembler” idea less useful because there’s less code written in that middle ground when you want either a higher-level representation which gives compilers more flexibility or precise control. For example, cryptography implementers want not just high performance but also rigid control of the emitted code to avoid a compiler optimizing their careful constant-time implementation into a vulnerability.
- ses1984 2y agoWhat optimizer would remove the increment/decrement if the value was accessed in between? That seems like something that would be really easy to detect. I’ve never studied compilers though.
- remexre 2y agoIt would be very normal for a compiler to do an increment (or merge it into a later instruction), but never do the decrement, and instead use the old copy of the value.
- 2y ago
- vikramkr 2y agoI'm pretty sure that's replying directly to the comment about how c is close to assembly and that if you add that line of code somewhere you know there's a variable getting incremented. Doesn't really matter whether or not it's useful, the point is that the behavior isn't exactly what you wrote
- jmillikin 2y agoTo reiterate, claiming that C can be described as "portable assembly" is not a claim that it is literally a package of assembler macros that emit deterministic machine code for each individual source expression. I linked these in another comment, but here's some examples of straightforward-looking integer addition emitting more complex compiler output for other languages that compile to native code: Haskell: https://godbolt.org/z/vdeMKMETT https://godbolt.org/z/vdeMKMETT C++: https://godbolt.org/z/dedcof9x5 https://godbolt.org/z/dedcof9x5
- eru 2y agoThe Haskell version deals with both laziness and also detects overflow. Your C++ example has a lot more code than the C example, I'm not sure why you'd expect it to produce the same output?
- johnisgood 2y agohttps://godbolt.org/z/r39jK1ddv https://godbolt.org/z/r39jK1ddv It increments, then decrements with -O0 though. I do not see the issue still, as the behavior is expected with -O0; increments then decrements.
- eru 2y agoThere's nothing in the C standard that enforces the observed -O0 behaviour. Your compiler might change tomorrow.
- johnisgood 2y agoHow likely is that to happen, and in which languages can you either optimize or not AND where the compiler might not change tomorrow though? David Hume said that we cannot know if the sun is going to rise tomorrow just because it has always did before. See "problem of induction", https://philosophynow.org/issues/160/Humes_Problem_of_Induction https://philosophynow.org/issues/160/Humes_Problem_of_Induct....
- chasd00 2y agoI'm not an embedded expert but a friend of mine has complained about compiler optimizations breaking things in his programs. I could see incrementing by one being used to set some bits in a memory location for a cycle that may mean something to some peripheral and then decrementing by one to set some other bits that may mean something else. In that case, the compiler removing those two lines would cause a very hard to debug issue.
- johnisgood 2y agoI understand compiler optimizations having unintended consequences, e.g. https://godbolt.org/z/r39jK1ddv https://godbolt.org/z/r39jK1ddv but there are a lot of options he may use to enable or disable optimizations (assuming GCC here): https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html This is even more difficult to do with higher-level languages.
- mkoubaa 2y agoIf you want the compiler to treat your code as literal portable assembly turn off optimizations.
- johnisgood 2y agoExactly, pretty much what I said, or enable / disable the optimizations you want.
- eru 2y agoThat's a property of a particular compiler, not of the C language (at least as described in the standard).