4 ms·
The following is NOT a criticism of C. Just pointing out different problem domains. > Modern high-level languages generally try to arrange that you don't need
by DannyB2 5y ago
The following is NOT a criticism of C. Just pointing out different problem domains.
> Modern high-level languages generally try to arrange that you don't need to think
> or even know – about how the memory in a computer is actually organised
Modern high-level languages try to arrange that you don't need to focus on the irrelevant. If you're working on, say, an accounting system, memory layout is not part of the problem you are trying to solve.
For certain applications, C is simply too low level.
A language is too low level when it forces you to focus on the irrelevant.
For low level operations you probably cannot beat C.
- kaba0 5y agoAs per the somewhat famous blog post: C is not a low-level language. Especially on todays CPU’s I fail to see why would we consider C anything close to truly low level. It has no real way of managing cache, has absolutely zero support for vector instructions, etc. * With these in mind, Rust is lower and higher level than C at the same time. * other than some compiler specific pragmas, but I would be hesitant to call that natively supported
- munificent 5y ago> Especially on todays CPU’s I fail to see why would we consider C anything close to truly low level. It's effectively the lowest you can go without throwing portability out the window. It doesn't let you manage caches directly, but it gives you good control over memory layout in general, and that's often enough to give you good cache usage across a variety of chips. If you want to go lower than that, you're probably looking for assembly.
- tialaramex 5y agoIt's a poor fit for this role, even if it is in practice what we have available today. One of my favourite examples is volatile. Volatile is more crazy in C++ but it's pretty crazy even in C. In both cases the standard basically shrugs, "Hope you know what you're doing because we sure don't" and offers no real insight into what this feature promises to do for you. But there is no other mechanism provided for MMIO. Think of Rust's std::ptr::read_volatile (and write_volatile). These intrinsics do the thing you actually wanted (reading, or writing, a fixed size blob of "memory" that presumably wasn't really just RAM) and thus are important for writing device drivers and so on with MMIO. [ You may be thinking, "But I need the correct size of blob read or written or my driver won't work", Rust has generics, so these functions are generic over the integer type you're reading/ writing, if you read a u64 that's a 64-bit read, if you write four u8s that 4 x 8-bit writes and so on ] But C's volatile is a type qualifier instead. Why? Would it mean anything to, for example, integer divide an MMIO fetch by fifteen and write it back? a/= 15; No. So then why make it a type qualifier? When volatile was added to C they'd only just invented simple optimisations like re-ordering so they had no idea this was a bad idea, and it seemed simpler than adding an intrinsic (though not by much) but today we know better.
- jstimpfle 5y ago> One of my favourite examples is volatile. It's strange that an ancient feature that is almost practically deprecated serves as one of your favourite examples. I'm not an expert, but volatile was originally meant to access hardware registers and I believe it did fulfill its purpose at the time. I've never reasearched the official definition of volatile, but it is widely acknowledged that there are few or even no legit uses of it today, because it is not suited to general concurrent programming. This seems like a good SO answer: https://stackoverflow.com/questions/2484980/why-is-volatile-not-considered-useful-in-multithreaded-c-or-c-programming https://stackoverflow.com/questions/2484980/why-is-volatile-... If I understand right, I think you could do multithreaded programming if you restrict to doing message passing of message structures that are marked all volatile. But you can't use much else, because non-volatile data accesses can be reordered around volatile data accesses. In short, probably just don't use volatile. Use the "modern" memory barriers, those exist in C/C++ just as they exist in Rust. > Would it mean anything to, for example, integer divide an MMIO fetch by fifteen and write it back? a/= 15; No. So then why make it a type qualifier? This seems a strange example to me as well. This is equivalent to (a = a / 15). I.e. a volatile read followed by a volatile write. Not defending volatile at all, but I can't see what is so wrong here. On a different note, attaching too many semantics to types is basically the complaint that I have about most languages. Types are too static and too inexpressive to capture all but the most trivial invariants, so complicated types often require messy and theoretically unnecessary workarounds. I always say, I'd almost like to types capture only the physical shape (sizes, alignment...) of the data, because that is extremely important for optimization and also it doesn't really change. In C, that is almost true, with some exceptions (signed/unsigned, and yes, the crufty volatile)
- jstimpfle 5y agoAddendum: Think about volatile like you think about const. If you use it to declare memory that is in fact different, it totally makes sense. If you do other weird things, it breaks (just like const). This is unlike signed/unsigned storage specifiers which are not really attributes of the memory, and which create some serious complexities that lead to weird situations. But for practical reasons there haven't been any successful attempts to get rid of them. Again, not defending volatile at all. Just saying that it probably made sense at the time at that it is not as ill-conceived as you imply. Volatile is cruft, but certainly does not disqualify the language. Just use modern synchronization primitives instead, like any other reasonable person.
- kaba0 5y agoI’m fairly sure that C++, Rust and Zig are just as much portable. Any reason for not having native support for vector instructions?
- pjmlp 5y agoI go just as low level as C with Object Pascal, Basic, Modula-2, C++, Ada compilers. Or by using any of the kids on the block from the last decade.
- WalterBright 5y ago> For low level operations you probably cannot beat C. It's not hard to beat it. For example, you cannot do vector operations in C. (Hence C compilers often offer extensions.)
- vitaminCPP 5y agoIf one of your requierements is performance, ressource efficiancy and responsiveness, memory layout is the opposite of irrelevant. I can't imagine living in a 3rd world country with today's electron's catastrophy.