10 ms·
> And that’s why C is still the best language for systems programming—it still lets you to do what you mean (the problem is that most programmers don’t really k
by davemp 9y ago
> And that’s why C is still the best language for systems programming—it still lets you to do what you mean (the problem is that most programmers don’t really know what they mean)
Honestly after a ~1yr of embedded C co-op/intership experience, I'm familiar enough but not too entrenched to say that C is not that great for embedded/systems. When you're dealing at the hardware architecture level you need more detail than C (or any PL) can reasonably provide.
C doesn't "let you do what you mean", it has no knowledge of special registers, interrupts, timers, DMA, etc. Companies have coped with a slew of macros that are just ugly to write with and make testing much more difficult than need be. If the language had actual support for embedded you'd see support for architecture strictly as libraries (which may be possible in C but certainly not ergonomic or supported by the culture around the language). Library architectures would make writing simulators and embedded unit tests __MUCH__ simpler.
Not to mention the minefield that is the undefined sections of the C spec. A lot of people "mean" for an integer to rollover, but that's undefined and the C spec doesn't care about what you "mean". [1]
Just today I meant for a constant lookup table not to be overwritten by the stack (I had plenty of unused RAM), but unfortunately C doesn't care what I meant. I had to dig around and find an odd macro to jam that data into program space--effectively hiring some muscle (gcc) to break the spec so it behaved the way I wanted. [2] I run into this sort of thing all the time. I know the C spec. I know my hardware. C doesn't care and needs to be beaten up. The only real benefit of C in these situations is that it's a huge sissy and people are really good at beating the piss out of it now.
I'm not very familiar with rust, but if it makes an honest effort to be ergonomic for embedded (might need to be forked). It will eventually crush C.
[1]: https://blog.regehr.org/archives/213 https://blog.regehr.org/archives/213
[2]: https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/Named-Address-Spaces.html https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/Named-Address-S...
- legulere 9y agoJust a tiny nitpick: Only signed integer overflow is undefined, unsigned integer overflow follows modulo arithmetics. It's pretty much impossible to remember all those details.
- davemp 9y agoYup. You'd probably like the first footnote if you haven't already read it.
- adrianratnapala 9y agoThese things originate in hardware variations. Apparently all architectures use binary the same way so unsigned overflow just drops the MSB. But signed integers aren't always two's complement, so there is variation. See, no tedious rules to remember, you just have to understand how computers work. But the C standards call such things "undefined behaviour" rather than "platform specific" behaviour, and then try to pretend that the compiler can abstract the underlying machine away. That is they pretend programmers can understand the standard, and don't need to know how computers work. The result is a maze of arbitrary - but historically rational - rules about when the compiler has to do something sane, and when it is allowed to do whatever the hell it likes to squeeze some micro-improvement from a benchmark.
- kbenson 9y ago> The result is a maze of arbitrary - but historically rational - rules about when the compiler has to do something sane, and when it is allowed to do whatever the hell it likes to squeeze some micro-improvement from a benchmark. Which is a nice way of saying that sometimes they'll decide to elide chunks of code because they would only be reachable because of undefined behavior, and if that elided code happened to specifically be checking for and handling that undefined case as an error, too bad.[1] :/ 1: https://news.ycombinator.com/item?id=14163111 https://news.ycombinator.com/item?id=14163111
- davemp 9y agoThinking about hardware is definitely the move when writing C. This is the major struggle with abstraction. We want to remove the burden of knowing the ins and outs of the target architecture. Inevitably, we create trouble and fall on our faces when it turns out that the hardware is still in fact there and doesn't like when we ignore it. It's really an impossible problem. One can't account for every architecture when designing a language. Likewise, one can't feasibly remember the details of every architecture while programming. Honestly I'd be interested to see some tools that approach the problem from a direction other than maximum portability. Not that I think they'd be popular or "good".
- jstewartmobile 9y agoIt sounds like you're looking for Forth. It doesn't have everything on your wish list, but it's a good bit more predictable when you have to get down into the weeds.
- m-j-fox 9y agoThumbs up for driving more nails into C's coffin. What any pretender to the throne needs most is C interoperability because we're stick with legacy code. You need to be able to just code in C when necessary including the datatype zoo, the unsafety and the ugly macros. If it takes even 5 minutes to wrap a C function for your new language, that's years of work for some codebases.
- Manishearth 9y ago> but if it makes an honest effort to be ergonomic for embedded There are constant improvements but I wouldn't say we're there yet. I think we will be though, embedded is something a lot of folks care about.
- steveklabnik 9y agoThe latest on this front: http://blog.japaric.io/rtfm-v2/ http://blog.japaric.io/rtfm-v2/
- test9753 9y agoFound this paper useful: "The Case for Writing a Kernel in Rust" (https://www.tockos.org/assets/papers/rust-kernel-apsys2017.pdf https://www.tockos.org/assets/papers/rust-kernel-apsys2017.p...) linked from the "tock os" blog post: https://www.tockos.org/blog/2017/apsys-paper/ https://www.tockos.org/blog/2017/apsys-paper/
- steveklabnik 9y agoYes, this is a good paper, but was posted after my comment :)
- davemp 9y agoGood to hear. I'm sure there is a large group of developers sitting on the sidelines that check in from time to time hoping to be able to leave C behind. Has anyone on the rust team tried reaching out to get input/contributions from companies who are heavily invested in the embedded world? I know xilinx pours a lot of effort into language research, they do seem like an very proprietary company though.
- Manishearth 9y agoWe reach out and talk with companies regularly. We are both happy to organize a meeting with companies who approach us, and often (~yearly) organize calls with multiple companies using or evaluating Rust at once whom we reach out to. I believe there have been some of these focused on embedded stuff, but I wasn't on these calls.
- cryptonector 9y ago"do what I want" usually means "simple ABI that is trivial to interface with" which means you "can layout structures the way you want" and "calling conventions are simple so you can call C from assembly and any HLL FFIs and vice-versa". Really, that's all. If it was possible to build C++ classes in C or assembly, it would be done. But it's not because C++ doesn't have the kind of ABI (or any) that would allow one to do that. Of course, in practice C only gets you 95% of the structure layout functionality you need, as the rules for packing structures and bitfields(!) aren't sufficiently nailed down. Still, 95% out of the box is pretty good, and with some care you can get 100%. This matters when writing, e.g., drivers, but also codecs for another example. Any systems programming language aiming to replace C has to provide support for a C-like ABI. I'm not praising C here, mind you. It can't be replaced (with Rust or similar) quickly enough.
- flavio81 9y ago> If it was possible to build C++ classes in C or assembly You would be surprised, but Object-oriented programming has been done in C many times... and even before C++ existed.
- cryptonector 9y agoI'm not surprised. But you'll note I said "C++ classes", and I did that for a reason: it's not possible to write C++ classes in C because there's no stable, public ABI for one to write to. (Well, for some compilers there may be a public ABI, and some might even be stable, but even so, it's a mess.)
- adrianratnapala 9y agoOn particular platforms they have nailed down the C++ layout enough to make this possible. I think windows did it for COM (or DCOM?). But in general you are right. On of the most infuriating things about fancy languages is the way they all have their own ABIs. I mean it's nice that they support special features through those ABIs, but standardized vtables and dictionaries would take us a long way. And Kudos to Microsoft for having a second crack at getting that right with .Net.
- wott 9y ago> C doesn't "let you do what you mean", it has no knowledge of special registers, interrupts, timers, DMA, etc. Special registers are just slots at specific memory addresses. As far as the rest is concerned, not a single language in the world will provide you with primitives for that and make them portable across a thousand architectures with a million different peripherals. That's the role of libraries and OSes with their drivers.
- davemp 9y ago> Special registers are just slots at specific memory addresses. > As far as the rest is concerned, not a single language in the world will provide you with primitives for that and make them portable across a thousand architectures with a million different peripherals. I'm well aware, that's why I said. > When you're dealing with the hardware architecture level you need more detail than C (or any PL) can reasonably provide. A language does not need to provide every hardware primitive, just realize that it can't and implement a sane way to support hardware features that don't require abusing a cumbersome macro system and heavy compiler modification. > That's the role of libraries and OSes with their drivers. A ridiculous amount of vulnerabilities and wasted effort are sunk into operating systems and their drivers because of the garbage state of tooling for low level work. It's easy to make statements such as yours until it comes time to write/maintain a multi million line kernel and a only the lord knows how many line driver/subsystem fleet. Kernel/driver devs do their best to make due, but the situation is far from ideal.
- nwmcsween 9y ago> A language does not need to provide every hardware primitive, just realize that it can't and implement a sane way to support hardware features that don't require abusing a cumbersome macro system and heavy compiler modification. The information has to somehow be passed to the compiler, your options are: compiler specific features (see gcc attributes, etc), language level (see the fun that becomes with explicit_memset vs. memset) or a really fancy IR that can hold these types of requirements.
- 9y ago
- flavio81 9y ago> And that’s why C is still the best language for systems programming I think the only reason C is very popular for systems programming is that it allows you to do most of what you could do in assembler, but in an easier-to-work way. So basically C is an "acceptable, easier-to-use assembler", but far from ideal, because of the reasons you point out. Honestly, the popularity of C itself is due to the success of UNIX, not due to any particular quality. On the other hand, the K&R "The C Programming Language" book is a classic, a well written book which surely does a great job of introducing the language. But back then in the late 1960s, a new language called ALGOL-68 was specified, back then a very advanced language which had powerful features even for 2017. The problem is that nobody dared to implement the full language. CPL was a stripped down implementation of Algol-68, this was then stripped down even more to BCPL; then it was extremely stripped down to B (only one datatype), then Dennis Ritchie kept most of the syntax and added other data types and C was born. C was never designed from the ground up to be the best systems programming language possible; only to be able to work for Dennis Ritchie & friends' "toy" operating system, UNIX, a very stripped-down MULTICS. I think the "UNIX-Haters Handbook" has a section devoted to C criticism.
- Nelson69 9y agoFor big computers, C is good for systems programming because everyone else uses it and because of the titanic effort that has been put in to building really good optimizing C compilers. UNIX came along but when C killed pascal, IBM, Microsoft, everybody was on C's dick. On small embedded computers, I think C is popular because it's so easy to build something that resembles a C compiler. The fact is, undergrad compiler classes almost build C compilers (some universities might actually go all the way.) You can almost build a yacc grammar that will read C and emit assembly. The small computer embedded vendors have a difficult problem, they need to provide tooling and they don't usually have giant piles of developers to sell to. So they dust off some abandoned "C compiler" they found in the gutter, add their hardware to it and call it good. At least that's my theory and I've seen some rough "compiler work" from some pretty substantial hardware vendors. In fact, if you're running a 16bit or smaller part or a weird part, I have yet to see a decent C compiler from a hardware vendor.