6 ms·
I have a question I've always wanted to know but too embarrassed to ask (Especially because I've extensively used C for well over a decade now and am intimately
by vbtemp 4y ago
I have a question I've always wanted to know but too embarrassed to ask (Especially because I've extensively used C for well over a decade now and am intimately familiar with it):
Who exactly are these new C-standards for?
I interact and use C on an almost daily basis. But almost always ANSI C (and sometimes C99). This is because every platform, architecture, etc has at least an ANSI C compiler in common so it serves as the least common-denominator to make platform-independent code. As such it also serves as a good target for DSLs as a sort of portable-assembly. But when you don't need that, what's the motivation to use C then? If your team is up-to-date enough to quickly adopt C23, then why not just use Rust or (heaven forbid, C++23)?
I'd love to hear from someone who does actively use "modern" C. I would love to be a "modern C" developer - I just don't and can't see its purpose.
- aidenn0 4y agoPlaces that are just now adopting C11 will probably adopt C23 in 12 years? C++ is (unfortunately, IMO) making inroads into embedded, but C is also still pretty widely used.
- connicpu 4y agoMany many many teams writing C won't be using C23 the day it's out, but they have to get these changes in now if they want the people who always use a 10 year old standard to have these features available 10 years from now
- layer8 4y agoExisting C code needs to be maintained, and can take advantage of the newer features when available in the compiler. The Linux kernel is moving to C11, and may move to C17/C23 later. Also not everyone wants to put up with the compilation times, object sizes, and aesthetics of Rust. As for new developments, see for example https://news.ycombinator.com/item?id=33675462 https://news.ycombinator.com/item?id=33675462 which uses C11.
- fweimer 4y agoI doubt that the kernel will adopt the C++ memory model (the big change in C11). Instead, they will keep doing their own thing. Given the problems with the memory model, I can't really fault them. But framing this in terms of standards versions is a bit of a stretch. They could easily adopt additional GCC extensions over time as they move minimum compiler versions forward. Standardization does not really matter there.
- electroly 4y agoAre you asking about greenfield development only? One big obvious reason to use C23 instead of Rust or C++23 is if you already have a codebase written in C. Switching to C23 is a compiler flag; switching to Rust is a complete rewrite.
- acuozzo 4y ago> Who exactly are these new C-standards for? An example: The C11 memory model + <stdatomic.h> + many compilers supporting C11 has/had a positive impact on language runtimes. Portable CAS! > If your team is up-to-date enough to quickly adopt C23, then why not just use Rust or (heaven forbid, C++23)? Another example: If you're programming e.g. non-internet-connected atomic clocks with weather sensors like those produced by La Crosse, then there's no real security model to define, so retraining an entire team to use Rust wouldn't make much sense. (And, yes, I know that Rust brings with it more than just memory safety, but the semantic overhead comes at a cost.) Another example: Writing the firmware to drive an ADC and broker communication with an OS driver. Another example: The next Furby!
- attractivechaos 4y agoAtomic is one of the few things in C11 I like most. Unfortunately, it is an optional feature along with threading [1]. It is not portable. In the end, I am still using gcc/clang's __sync or __atomic builtins. [1] https://en.wikipedia.org/wiki/C11_(C_standard_revision)#Optional_features https://en.wikipedia.org/wiki/C11_(C_standard_revision)#Opti...
- fweimer 4y ago<stdatomic.h> is provided by GCC (not the libc), so I expect it to be available everywhere the atomic builtins are supported. I prefer the builtins. With _Atomic you can easily get seq-cst behavior by mistake, and the <stdatomic.h> interfaces are strictly speaking only valid for _Atomic types.
- acuozzo 4y ago> Unfortunately, it is an optional feature along with threading [1]. It is not portable. Portability isn't binary. It's the result of work being done behind-the-scenes to provide support for a common construct on a variety of hardware and operating systems. It's a spectrum. GCC certainly is portable, but it doesn't support every ISA and OS. Over time it has even dropped support for several. Random thoughts since I'm still in the process of waking up… 1. Most of <stdint.h> is optional 2. long is 64 bits on Tru64 Unix which is valid under all versions of the standard
- gavinhoward 4y agoI'm also a C developer, but I do use the more modern versions. There are four big reasons why: * Atomics. These are the biggest missing feature in older C. * Static asserts. I can't tell you how much I love being able to put in a static assert to ensure that my code doesn't compile if I forget to update things. For example, I'll often have static constant arrays tied to the values in an enum. If I update the enum, I want my code to refuse to compile until I update the array. I have 20 instances of static asserts in my current project. * `max_align_t`. It's super useful to have a type that has the maximum alignment possible on the architecture. * `alignof()` and friends. It's super useful to get the alignment of various types. Combined with `max_align_t`, it is actually possible to safely write allocators in C. Previously, it wasn't really possible to do safely or portably. And I have at least three allocators in my current project. You're right that C11 doesn't have nearly the reach the ANSI C does, but it does have slightly more than Rust, much more if you consider Rust's tier 3 support to be iffy, which I do. And it does have one HUGE advantage against Rust: compile times. On my 16-core machine, I can do a full rebuild in 2.5 seconds. If I changed one file in Rust, it might take that long just to compile that one file. That's not to say Rust is without advantages; one of my allocators is designed to give me as much of Rust's borrow checker as possible, on top of API's designed around that fact. tl;dr: I use modern C for a few features not found in C89, for the slightly better platform support against Rust, and for the fast compiles.
- fweimer 4y agoExcept for max_align_t (which is broken even for scalar types on some targets, and doesn't help with vector types by design), all these things were available long before standardization. So I'm not sure if this is a compelling argument for standardization.
- ghoward 4y agoWithout standardization, I have to rely on specific compilers. That's not great, either.
- zozbot234 4y agoC provides the only stable ABI for Rust, and changes to the C++ ABI may also occur in the future. So the implications of new C standards for library code are especially relevant.
- flohofwoe 4y agoIn my case: because writing C code (specifically C99 or later - designated init and compound literals!) gives me joy in a way that neither C++ nor Rust provide (C++ was my go-to language for nearly two decade between ca. 1998 and 2017), and I tinkered with Rust a couple of years ago, enough that I realized that I don't much enjoy it. IMHO, both C++ and Rust feel too much like puzzle solving ("how do I solve this problem in *C++*" or "how do I solve this problem in *Rust*?"), when writing C code, the programming language disappears and it simply becomes "how do I solve this problem?"). PS: I agree that the C standard isn't all that relevant in practice though, you still need to build and test your code across the relevant compilers.
- anfilt 4y ago"IMHO, both C++ and Rust feel too much like puzzle solving ("how do I solve this problem in C++" or "how do I solve this problem in Rust?"), when writing C code, the programming language disappears and it simply becomes "how do I solve this problem?")." This statement very much resonates with me. It's honestly one of the things I like about C. Although it's not perfectly like this for me all the time. For example string manipulation is not great. An other aspect I like about C is there is not a plethora ways of doing the same thing which I have found always made it more readable than rust and C++.
- mathstuf 4y agoMaybe we just work on different kinds of software, but I feel like I'm actually solving problems in Rust when I'm using it. I don't have to think about all the terrible string manipulation APIs and how they can come back and bite me, who owns what is something I still have to decide except that the compiler actually helps out, and I have access to nice APIs that solve ancillary problems for me already (e.g., rayon, serde, etc.). I can't wait for the day when another parser will never be written in C again. In C, I feel like I'm building a house out of tinker toys, C++ is Lego Techniks, and Rust I'm using bricks and mortar. FWIW, Python feels like waterballoons and drywall to me; while it might look OK from the outside, one thing pierces your exterior and things tend to sag sadly from there.
- 4y ago
- davidtgoldblatt 4y agoMy usages are similar to yours, but new C standards still benefit me because I can opportunistically detect and make use of new features in a configure script. To use my baby as an example: free_sized(void *ptr, size_t alloc_size) is new in C23. I can detect whether or not it's available and use it if so. If it's not available, I can just fall back to free() and get the same semantics, at some performance or safety cost.
- Bhurn00985 4y agoI don't fully understand the need or benefit of having free_sized() available tbh. Spec says it's functionally equivalent to free(ptr) or undefined: If ptr is a null pointer or the result obtained from a call to malloc, realloc, or calloc, where size size is equal to the requested allocation size, this function is equivalent to free(ptr). Otherwise, the behavior is undefined Even the recommended practice does not really clarify things: Implementations may provide extensions to query the usable size of an allocation, or to determine the usable size of the allocation that would result if a request for some other size were to succeed. Such implementations should allow passing the resulting usable size as the size parameter, and provide functionality equivalent to free in such cases When would someone use this instead of simply free(ptr) ?
- jabl 4y ago> I don't fully understand the need or benefit of having free_sized() available tbh. It's a performance optimization. Allocator implementations spend quite a lot of time in free() matching the provided pointer to the correct size bucket (as to why they don't have something like a ptr->bucket hash table, IDK, maybe it would consume too much memory overhead particularly for small allocations?). With free_sized() this step can be jumped over.
- Bhurn00985 4y agoThanks for your insights, which prompted to actually jump into the malloc.c implementation.
- 4y ago
- fulafel 4y agoOld software is very slow and expensive to change. Adopting a new C version doesn't need a failure prone expensive synchronized collective-action rewrite throughout your sectors supply chain, new tooling, platform runtime ports, etc. Rust would.
- jrmg 4y agoOutside our bubble, there’s an _ocean_ of embedded software/firmware and lower level library stuff, on up-to-date platforms, written in C by people or teams that would find switching to Rust just a _massive_ chore. I’d guess there is at least an order of magnitude more of this than Rust. And I certainly appreciated C11 when writing Objective-C, so I’m sure people with large codebases of ObjC will appreciate it (though most will be using Swift for new features nowadays).
- addaon 4y agoKeep in mind that if you want to write probably-maybe-correct code, Rust is maturing to be able to get you there more easily than C. But if you want actually-correct code, you need to do the legwork regardless of language; and C has a much more mature ecosystem (things like CompCert C, etc) that lets you do much of the analysis portion of that legwork on C code, instead of on generated assembly code as you'd have to do for Rust. Combined with verification costs that don't vary that much from language to language, and there's a long future where, for safety-critical applications, there's no downside to C -- the cost of verification and analysis swamps the cost of writing the code, and the cost of qualifying a new language's toolchain would be absurd. For this reason, C has a long, long future as one of the few languages (along with Ada, where some folk are making a real investment in tool qualification) for critical code; and even if it takes a decade for C23 features to stabilize and make it to this population, well, we'll still be writing C code well beyond '33.
- MaxBarraclough 4y ago> Combined with verification costs that don't vary that much from > language to language, and there's a long future where, for > safety-critical applications, there's no downside to C -- the cost > of verification and analysis swamps the cost of writing the code That doesn't sound right. You really want to get the code right early on. The later bugs are discovered, the more costly the fix. You may have to restart your testing, for instance. If the language helps you avoid writing bugs in the first place, that should translate to quicker delivery and lower costs, as well as a reduced probability of bugs making it to production. The Ada folks are understandably keen to emphasise this in their promotional material. > the cost of qualifying a new language's toolchain would be absurd As I understand it, this typically falls to the compiler vendor, not to the people who use the compiler. A compiler vendor targeting safety-critical applications will want to get their compiler certified, e.g. [0]. To my knowledge we're nowhere near a certified Rust compiler, although it seems some folks are trying. [1] [0] https://www.ghs.com/products/compiler.html https://www.ghs.com/products/compiler.html [1] https://ferrous-systems.com/blog/sealed-rust-the-pitch/ https://ferrous-systems.com/blog/sealed-rust-the-pitch/
- enriquto 4y ago> Who exactly are these new C-standards for? For me and for many colleagues in my lab? C is quite big in scientific computing and signal processing. Fortran would be slightly better, and it is widely used, but not directly around me. The C99 standard, which added complex numbers and variable length arrays, was truly a godsend in the field. I cannot imagine working without it. If you write a numerical algorithm that needs to be run 15 years from now, then C and Fortran are possibly the sanest choices. If you do something in other, fancier, languages, you can be sure that your code will stop working in a few years. The new C standards are really minor changes to the language, and they happen in the span of a decade. It is quite easy to be up to date. And in the rare case that your old code stops compiling, the previous (less than a handful) versions of the language are all readily available as compiler options in all compilers. You can be reasonably sure that a C program written today will still compile and run in 20 years. You can be 100% sure that a python+numpy program won't. If you care about this (for example, if you are writing a new linear algebra algorithm to factor matrices), then choosing C is a rational, natural choice.
- hutrdvnj 4y ago> You can be 100% sure that a python+numpy program won't. It's possible to use a phyton+numpy program in 20 years, but you also have to save the entire environment and make sure that it works air-gapped (otherwise external dependencies would fail). One possiblity would be to store it as a qemu virtual machine. It's very possible today to boot up stuff as VMs that is 20 years and older (e.g. 20 year old Linux distros or Windows XP iso from early 2000s).
- quelsolaar 4y agoI'm in the WG14, and I, like you, only use c89. So why does c23 matter? Well in terms of features it matters very little but a big part of wg14s work is clarifying omissions from previous standards. So when c23 specifies something that has been unclear for 30+ years, compiler developers back port it in to older versions of C where it was simply unclear. It matters a lot for things like the memory model and things like that.
- vbtemp 4y agoThat's very interesting. Thank you.
- kazinator 4y ago> compiler developers back port it in to older versions of C where it was simply unclear You cannot rely on that. If you're maintaining C90 code, with a C90 compiler or compilation mode, you should go by what is written ISO 9899:1990, plus whatever the platform itself documents. We actually don't want compiler writers mucking with the support for older dialects to try to modernize it. It's a backward-compatibility feature; if you muck with backward compatibility features, you risk breaking ... backward compatibility!
- kccqzy 4y agoAt least for C++ there is something called defect reports. When agreed, those defect reports to retroactively applied to previously published C++ standards. As a random example for something as fundamental as classes in C++, the page https://en.cppreference.com/w/cpp/language/classes https://en.cppreference.com/w/cpp/language/classes shows ten defect reports.
- quelsolaar 4y agoC cares a hell of a lot about backwards compatibility. Whenever there is a corner case that gets fixed, the number one goal is to retain compatibility. most of the time, these clarifications clarify what everyone is already doing and has been doing for decades. Also, most of these corner cases are so obscure that the vast majority of people with decades of C experience have not encountered them. C is an extremely explored space.
- LAC-Tech 4y agoIf your team is up-to-date enough to quickly adopt C23, then why not just use Rust There's a lot of reasons to use C23 over rust - multiple compiler implementations - works on more platforms - defined standard - ability to create self-referential data structures without hacky workarounds - immediate, easy access to large numbers of C libraries (For the record I like rust, but the evangelism over the past half decade has been pretty ridiculous. Consider this counter propaganda).
- sharikous 4y agoThere is no "modern" C but "C with additional niceties". And those additions are usually low key enough to be adopted by a good portion of the compilers out there. When you have a C code base or experience with C those features may be enough not to make a complex transition. Having a simple tool evolve a bit may be what you need as opposed to making the change to a much more complex tool.
- torstenvl 4y agoOne thing I'm really looking forward to is standardization of binary literals. Bitwise masking makes a lot more sense with binary literals than hex literals. Example: https://pasteboard.co/VkjrJIOZzaiR.jpg https://pasteboard.co/VkjrJIOZzaiR.jpg (Sorry for pasting code as an image, I'm on my phone)
- fweimer 4y agoI believe the current WG14 charter is here: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2611.htm https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2611.htm This text is still in force, it seems: “ 13. Unlike for C99, the consensus at the London meeting was that there should be no invention, without exception. Only those features that have a history and are in common use by a commercial implementation should be considered. Also there must be care to standardize these features in a way that would make the Standard and the commercial implementation compatible. ” I read this as saying that anything that gets standardized should be available in one of the major implementations. In practice, most of the qualifying features will have been implemented in both GCC and Clang in the same way, so for most users, there is not much benefit from standardization. Some may feel compelled to support the ”standard” way and the “GCC/Clang” way in the same sources, using a macro, but that isn't much of a win in most cases. Of course, there will be shops that say, “we can't use feature until it's in the standard”, but that never really made sense to me. Things are considerably murky on the library side. In my experience, library features rarely get standardized in the same way they are already deployed: names change, types change, behavioral requirements are subtly different. (Maybe this is my bias from the library side because I see more such issues.) For programmers, the problem of course is that typical applications do not get exposed to different compiler versions at run time, but it's common for this to happen with the system libraries. This means that the renaming churn that appears to be inherent to standardization causes real problems. Others have said that new standards are an opportunity to clarify old and ambiguous wording, but in many cases the ambiguity hides unresolved conflict (read: different behavior in existing implementations) in the standardization committee. It's really hard to revise the wording without making things worse, see realloc. So I'm also not sure what value standardization brings to users of GCC and Clang. Maybe it's different for those who use other compilers. But if standardization is the only way these other vendors implement widely used GCC and Clang extensions (or interfaces common to the major non-embedded C libraries), then the development & support mode for these other implementations does not seem quite right.