7 ms·
Friendly local C programmer and compiler writer here to remind you that C definitely is a low level language for those who understand it and use it professional
by pizlonator 3y ago
Friendly local C programmer and compiler writer here to remind you that C definitely is a low level language for those who understand it and use it professionally. If you’re looking for a low level language, then C (and its relatives) are your best bet.
If you’re new to the language and want to understand how to use it like a pro then ignore this post - it will only confuse you and reduce your ability to use C effectively.
- pjmlp 3y agoOnly when taking into account language extensions that are compiler specific and not part of ISO C. Also a reminder that any language can have toolchains with extensions exposing low level features.
- deleted 3y ago[deleted]
- hardware2win 3y ago>use it professionally I think this post goes way way way above boringness of day2day jobs. Yea, this post is not about how to use hammer, but more like curious consideration whether using hammers everywhere is not limiting us (C design)
- lelanthran 3y ago> Yea, this post is not about how to use hammer, but more like curious consideration whether using hammers everywhere is not limiting us (C design) Maybe it [EDIT: the post] is, but the title is obviously nowhere near accurate - if C is not a portable low-level language, what on earth is? [1] It gets reposted everywhere so often I have read it multiple times, and the one thing in common I see is how every know-it-all crawls out of the woodwork to comment on the title, as if the title was something new, deep, profound or even correct.
- rfoo 3y agoThe post argues that there is no portable low-level languages, including C. i.e. truly low-level languages can't be portable and is bound to the architecture.
- scythe 3y agoIt's plausible that a language could expose some general logic behind instruction-level parallelism and cache management — even register renaming — without being explicitly tied to the way one particular architecture does that. I have no idea how to design such a language, but from 10000 meters I think it could be done. I think the author oversteps his case by suggesting that ILP is an abomination that exists to preserve the availability of C-like languages. In my experience, many algorithms seem to naturally lend themselves to ILP, and I often find myself wondering whether I have typed them in so that these five lines will in fact run simultaneously. One common flaw in critiques of the common C compiler model is that they all seem afflicted by a nostalgia for Lisp machines, when the space of unexplored possibilities is so much larger.
- bayindirh 3y agoC is only portable between systems which emulate PDP-11 at hardware level and if and only if you don't use any compiler-specific extensions. If you use sys calls, work between different breeds of operating systems (UNIX, POSIX and Windows are not compatible with each other), you need to rewrite or wrap relevant parts, or write the relevant part beforehand inside ifdefs to be able "port" it between systems. The gist of the piece is, hardware is evolving to please C's programming model, hiding all the complexities C is not aware of, and behave like a PDP-11 on steroids. This is why we have truckload of side-channel attacks in X86 to begin with. To "emulate" PDP-11s faster and faster.
- Joker_vD 3y agoIt's not even that faithful to PDP-11, either. PDP-11 has unified integer division/modulo instruction (and it operates in double-width: it takes 32-bit dividend and 16-bit divisor and produces 16-bit quotient and remainder, just like x86), it has double-width integer multiplication (again, just like x86), it has instruction for addition/subtraction with carry — nothing of that is available from (standard) C, and it's quite a pity. And also, while PDP-12 it has built-in support for post-increment and pre-decrement for pointers, it doesn't has built-in pre-increment or post-decrement.
- quelsolaar 3y agoYour friendly wg14 member here. It is a low-level language, but it is not a portable assembler. If you think you what you will write will have a one-to-one relationship to assembler you will run in to trouble. If you want a deeper dive in to how these things can trip you up, watch: https://youtu.be/w3_e9vZj7D8 https://youtu.be/w3_e9vZj7D8
- gavinhoward 3y agoC programmer and fan of yours. I agree with you, but if you could convince WG14 to remove a lot of the stupid UB, that would be closer to the case. (I know you're trying from your "One Word Broke C" article. Which, by the way, is putting up a server error right now.)
- pif 3y ago> it is not a portable assembler And it never was! Just keeping this point in mind would reduce the plethora of discussions about undefined behaviour to the essential, i.e. the useful discussions, i.e. the 0.1%.
- JonChesterfield 3y agoOpinion is divided on this. My best guess is that ISO C was never a portable assembler, but the C programming language before standardisation broadly was, and that's how people hold both positions as self evidently true. Different definition of "C".
- pif 3y agoProgrammers are supposed to trust official interfaces rather than undocumented implementation details ;-P
- pizlonator 3y agoDepends on what you mean by "portable assembler". It is exactly that in a lot of ways, but exactly not that in others. I think it's more useful to say that C is a portable assembler, than it is to say that it isn't, considering how it's used in practice and the sort of nasty things C compilers do in order to make that possible.
- hcks 3y agoFunny how the top comment on "hacker" news is an *unsubstantial* comment about how, actually, TFA is wrong. Even worse, adding a comment on how actually you shouldn’t be curious and understand how things really work.
- deleted 3y ago[deleted]
- cmsonger 3y agoThe author is playing a semantic game. I don't think the author's point is that "C is not a good language for systems programming." You are not going to have an equivalent to volatile int *dma_register = SCATTER_GATHER_BASE; in Haskell. The author's point is that the drive to make C and other "model the von Neumann machine" languages execute quickly has made the compiler very complicated (the author is implying that "low level requires simple compiler") and that processors built to make such code run quickly are also very complicated. And those complications carry costs. In many ways this is a "call to programming model action" and cites GPU as illustrating the potential when "new programming model" and "silicon to support it" are done in concert.
- jerf 3y agoC is a low level language... but it's the wrong low-level language. It gives you low-level access to a machine that your real machine actually has to somewhat laboriously emulate. Such dangly bits and bodges that have been added over the years to give access to the real machine are relatively foreign bodies to C. I would agree the title is a bit rhetorically rough, though, because being the wrong low-level language doesn't make it a high-level language. WASM would similarly be "wrong" if I claimed it was a direct mapping to modern hardware, but that doesn't make it "high level". (Although what really frustrates me about C isn't that it's a bad mapping per se. It's from the 1970s, what do you expect? And it is obviously still quite useful for many cases. What frustrates me is that it continues to a large degree to dictate language design and heavily color how language designers see hardware, so too much modern language design is still just reshuffling bits of C around, rather than building languages that work with the hardware well.)
- hawk_ 3y agoWhat language(s) in your opinion have the right low-level where the access to the real machine doesn't feel foreign?
- giancarlostoro 3y agoThe only one I can think of would-be Assembly, but I don't do much low-level work, I code in much higher-level languages. Genuinely curious what the answer is.
- actionfromafar 3y agoI don’t think there is one, and if there was, it would run the same risk of becoming anachronistic as C itself has. Besides, C and its compilers have very much influenced CPU designs and optimisations, so it’s a world with a feedback loop. Maybe the loop will weaken somewhat in the new LLM craze.
- schwoll 3y agoFor portability by far the vast majority will say C. In my experience the C compiler optimizer will do a lot with -O2 or -03 but it can't always infer correct SIMD optimization for some operations and on occasion you have to drop down into x86_64 assembly. The idea is do most things in C and use __asm__ to write custom assembly instructions. With #defines around the assembly for each processor you plan on supporting you get the benefit of both C optimizers and portability across different CPUs as well as any future updates to the compiler in the future. But the compiler writers will say to use intrinsics and extended assembly rather than raw assembly because when you write raw assembly your code becomes a black box to the compiler and it can't infer optimizations for your surrounding code that interfaces with the assembly. I think C with extended Asm is likely the most sane combination if you don't mind the slightly ugly syntax and the fact that there could be differences between compilers. That being said, C with compiler intrinsics seems to be a happy compromise for those that don't want to shift around registers and deal with the stack. https://gcc.gnu.org/wiki/DontUseInlineAsm https://gcc.gnu.org/wiki/DontUseInlineAsm https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html I don't use Rust so I can't comment on it but it also has compiler intrinsics + a memory safety model. It's compiler is really dog slow last time I used it so I hope that has improved but nobody is really killing C any time soon, even if there's enthusiasm for memory safety. Sooner or later you have to delve down into the depths of Narnia and you may as well get comfortable dealing with memory. My likely favorite combination is Python + C (for the speed stuff) + Intrinsics (for the really speed stuff).
- spion 3y agoCan you elaborate?
- bunderbunder 3y ago"Low-level" is a word with multiple meanings. The original one is the one the article uses: low-level languages are non-portable and tied to the hardware on which they run, and high-level languages can target multiple platforms. Under this definition, C is absolutely a high-level language. My complaint would not exactly be that the author is playing semantic games; it would be that they are clinging to archaic terminology in a way that does more to confuse than enlighten. The "generations" taxonomy is generally more descriptive. 1st: Machine 2nd: Assembly 3rd: General-purpose 4th: Application-specific The 3rd/4th distinction gets a bit muddied sometimes, and back in the 80s and 90s people talked about a 5th generation that never really took off. But a couple (I think) clear examples of 4GLs are SQL, HyperCard, and Mathematica. What I like about that approach is that it mostly breaks languages up according to fairly clear distinctions about when you would use them. And then we can use "high/low-level" as a relative term, where higher-level languages tend to do more to abstract away the details of what the computer is actually doing. That does mean that higher-generation languages tend to be higher-level; all we lose in doing it that way is the ability to have silly arguments about where to place a completely arbitrary (and, frankly, useless) dividing line. I also like that this way we can recognize .NET IL, WebAssembly, and Java bytecode as very high-level 2nd generation languages, which, at the very least, is fun. Oh, and Forth is a 3rd generation language. Fight me, Chuck.
- fanf2 3y ago5th generation was the label under which the Japanese government threw a lot of money at Prolog and expert systems. It wasn’t a technically-driven distinction from the 4th generation, but rather a wish about what would happen if the project succeeded. 5GLs came about from language designers bidding for research money, saying, try our language, it’s better than Prolog!
- titzer 3y agoThere's a lot of moaning and crowing here, but no real substance. If one were to design a CPU and its ISA from scratch, what would you do? Instructions, control flow, memory, out-of-order execution, caches, hierarchies, branch prediction, you'd probably end up with all of it down there anyway. I don't get the point about GPUs. Real applications aren't matrix multiplies and embarrassingly parallel numeric algorithms, they run general purpose PLs. Which basically then boils down to ISA design. If you could design an ISA from scratch for the hardware you design from scratch, what would you do? Well, there aren't that many options. Stack machine, dataflow machine, VLIW machine. All of those have been tried and the modern superscalar CPUs kick their butts on every metric except power. The whole article kind of misses the point anyway. We should probably be running higher level languages for most things anyway, which shouldn't be overly constrained by hardware design. For everything else, 100% serious, there is WebAssembly, and hardware ISAs will fade below this level of abstraction in the fullness of time.