4 ms·
> I want behavior matching my architecture. Then use assembly. C is meant to abstract CPU architecture away.
by pif 2y ago
> I want behavior matching my architecture.
Then use assembly. C is meant to abstract CPU architecture away.
- vbezhenar 2y agoUsing just assembly is not realistic. I'd love C-like language which compiles to assembly in an understandable way. I mean that optimizations are certainly useful and needed. I want to write `24 * 60 * 60` and expect for compiler to multiply those values at compile time. I want to write debug logging which could be disabled for release build and all relevant variables and functions be excluded. Basically there are reasonable optimizations which I would expect for compiler to do. Anyway it's not like there's a choice in reality. Manufacturer provides SDK and examples with C, using another language for most projects is not realistic.
- pif 2y ago> Using just assembly is not realistic. And using C as fully deterministic is idiotic, considering the effort that went into specifying in great details everything that is NOT deterministic. > I'd love C-like language which compiles to assembly in an understandable way. Which is orthogonal to its purpose. A compiler's job is to provide the fastest code that implements what your (correct) code specified. Readability is pointless for generated code, as it not meant to be read nor modified.
- rstuart4133 2y ago> Then use assembly. C is meant to abstract CPU architecture away. Maybe. Looking back, I'd describe C as a portable assembler. K&R only optimised CPU architecture away when it was efficient to do so. For example, it wasn't efficient to specify the signed-ness of a char - so they didn't. Likewise the result of modulo ('%') on a negative number was undefined. Even the size of an int was undefined. In all these cases you get what the hardware gives you - just like you do in assembler. I think that was the right decision. It was the best that could be done at the time. The price of the abstractions languages put in place in the name of safety and convenience meant they were a poor fit for embedded and system work. Consequently C has had decades of dominance in it's niche, a success that speaks for itself. Now a plausible challenger has arisen, but it's taken forever in internet time. What I will criticise is what came after K&R. In K&C Undefined Behaviour meant "you get what the hardware gives you". Since what the hardware did was always well defined with a given compiler and arch everything the behaviour of your code was 100% deterministic. Then the compiler writers seeking to produce faster code twisted the definition to mean "if the behaviour is undefined we can do whatever we damned well please in order to generate faster code". And with that, at different optimisation levels code started to do different things. The C++ plumbed the depths of this idiocy by definite infinite loops as UB. I have no idea why - embedded computers, services on modern OS's and even OS's themselves have infinite loops at their core - loops running until the electrons are removed is exactly the behaviour the programmer is depending on. It's idiocy because the halting problem (and ergo whether a particular loop is infinite) is famously not decidable. So they've undefined behaviour in a way that itself isn't defined. In practical terms, this means you write an infinite loop you are making a bet some you've made so convoluted a future version of the optimiser won't spot it. It's a bet some the occasional person has lost when they moved to a new version of the compiler. It is possible to signal to the compiler the loop must stay regardless, but you have to be a language lawyer to know how, and most don't. So yes for today's C you are right, it is not assembler. In some ways it's objectively worse, as assembly is always well defined.
- pif 2y ago> In K&C Undefined Behaviour meant "you get what the hardware gives you". No, what you are talking about is "implementation-defined". Out of all trades, programmers should know better than everybody else to code against the specification rather than the implementation. If your code worked with K&R compiler by chance, and not by contact, then your code is wrong. Period.
- rstuart4133 2y ago> No, what you are talking about is "implementation-defined". Fair enough, with one qualification. K&R uses the phrase "behavior is undefined" very frequently. Almost every use in fact means what you term "implementation-defined". The one exception I could find is reading an the uninitialised variable, where what you read may be truly undefined. In K&R they feel to need to clarify that particular usage of "undefined" by saying "have undefined (i.e., garbage) values". Even in that case, you are getting whatever the hardware gives you. For example, K&R says "The effect of the call is undefined if the number of arguments disagrees with the number of parameters in the definition of the function". That only makes sense if it means "The effect of the call is implementation defined" because we make such calls it all the time, and rely on the outcome being completely deterministic. Or in their description of comparing pointers: "But the behavior is undefined for arithmetic or comparisons with pointers that do not point to members of the same array." And indeed it is not defined by C, but what happens is well defined by many implementations and embedded C programmers rely on it. Contrast that to the current meme "if the compiler detects undefined behaviour, it may do whatever it damned well pleases and that may change depending on optimisation level or version, or even on the order you compile your modules" doesn't appear in K&R. If it did mean that the K&R compiler would be fully entitled to remove an if and it's else when it depended on the comparison between pointers to different arrays. And if it detected a negative shift it could delete the instruction entirely instead of emitting it and letting the hardware do whatever it does with negative shifts. The old C compilers did not do that, ever, because K&R's "behaviour is undefined" did not give that sort of licence. Renaming K&R's "behaviour is undefined" to "implementation defined" and appropriating "undefined behaviour" for entirely different usage seems like word games to me.