The Assembly like abilities have been growing as language extensions in specific compilers, not as part of ISO C.
Going back to K&R C, inline Assembly or intrisics were not even available, all of that required using the Assembler directly.
C exists in a nether world of being neither assembly nor high-level language.
People only call it high level because in the 1970s, having blocks, loops, and functions was high level, compared to the SoTa machines available in the day, which were either programmed with assembler or some bespoke thing the manufacturer came up with.
But it is also wrong to reduce a language to what is in the spec.
Apparently reducing the language to what is in the spec is only a thing when talking about C and to some extent C++.
When other languages have compiler specific extensions beyond the spec, it is a failure in their design.
Yet when C and C++ devs have to reach out to compiler specific extensions, it is not a design failure like it is pointed out to others, rather an advantage.
It is also wrong to not apply the same measure when it doesn't suit the message.
It was already outdated by the time Borland released Turbo C++ 1.0 for MS-DOS, and only got new wind thanks to GNU FOSS and their manifest to prefer C as the main compiled language for GNU projects.
Everywhere else outside UNIX, was going with a mix of C++ for OS frameworks, Apple, Microsoft, IBM, Be, Nokia, Epoch,....
Naturally given the option, between C, C++ and something else I might prefer that something else, however I managed a few interesting positions exactly due to my C++ skills, and interests.
So don't mix my preferences for C and C++ on the same basket.
> So don't mix my preferences for C and C++ on the same basket.
That mistake is mine indeed, I'll remember. Thanks, and I hope "no harm meant" was implicit :)
Two measures two weights, in C versus other systems languages.
This one of the failures of Linus T. with the linux kernel: he was not able to keep the assembly source code with plain and simple C code you can compile with a small and alternative C compiler (same failure for the glibc devs I think).
I don't blame him, he is already keeping the linux ABI stable, and pulling that off is something.
Any code that ventures anywhere near that territory is 99% Undefined Behavior. It's almost impossible to write proper C/C++ code that isn't UB while touching byte-level representations.
ABIs are defined by CPU and operating system vendors. Those ABIs usually happen to be quite 'C friendly', but that's not a requirement (for instance the AmigaOS ABI was primarily meant to be used from handwritten assembly code, and Amiga C compilers had to adapt to those ABI rules or they wouldn't be able to call into operating system DLLs).
Personal pet theory: C is portable as in "you can retarget the compiler to any machine" moreso than "your code will run on any machine".
This is actually how c grew up. This is also one of the reasons why the spec is quite ambiguous in certain locations. C is made to be easily portable not a universal codebase for all platforms (though you can get quite close with some tricks like macros). Remember the spec allows C to run on a Unisys 1100/2200 just as well as on a pdp-11.
I may be to embedded for this but if you want your code to handle long long as int64_t use <stdint.h>. I am of the opinion that you should always use fixed width types as portable types are a huge footgun and kind off redundant.
Especially when you start doing a little more complex things expecting them to work exactly the same, like 128bit values on a 64bit platform.