top | item 39081948

C23: A Slightly Better C

216 points| mfiguiere | 2 years ago |lemire.me | reply

169 comments

order
[+] flohofwoe|2 years ago|reply
A small improvement in C23 - but probably my favourite - is that it finally allows writing:

   struct bla_t bla = {};
...instead of

   struct bla_t bla = {0};
This was one of those pointless differences between C and C++ which caused a lot of grief when writing code in the common C/C++ subset.

PS: also func() now actually is the same as func(void), and unnamed parameters are allowed.

[+] kevin_thibedeau|2 years ago|reply

  The eighth line uses the static_assert keyword, which is a feature of C++11
C11 already had _Static_assert() and static_assert() in assert.h
[+] z_open|2 years ago|reply
The auto keyword seems like a strange addition given it's already a C keyword with a different meaning and this change won't help developers that much. It's more useful in C++.
[+] synergy20|2 years ago|reply
based on https://en.cppreference.com/w/c/compiler_support/23

even the newest clang does not support many of the c23 features.

gcc13 is much better, only a very few c23 are yet to be supported.

this is a long standing problem with clang/clang++: they're used in many linters and intellisense but they're lagging behind by a lot comparing to gcc.

[+] xxpor|2 years ago|reply
>they're used in many linters and intellisense but they're lagging behind by a lot comparing to gcc.

Pure speculation, but I wouldn't be surprised if these two were directly related to each other. Clang/LLVM is more modular, which makes it easy to write new things that integrate it (like a linter), but this can slow down adding new things that change the data model and external interfaces. GCC is the opposite: one big blob that makes it easier to add things since the surface area is lower.

[+] slacka|2 years ago|reply
All of the features descried in the article are supported by clang except maybe for the constexpr keyword. By your own list, neither one supports all the features. Also, gcc only supports about 4 or 5 features more than gcc, and clang supports a few gcc doesn't. Hardly "much better".
[+] ronsor|2 years ago|reply
Pelles C for Windows actually supports all (perhaps missing one or two) C23 features, even `#embed`.
[+] liquid153|2 years ago|reply
No mention of typed enums and nullptr. Small things but makes dev experience better
[+] keithnz|2 years ago|reply
Interesting to see they are removing some of the quirkier things...

- Remove Trigraphs.

- Remove K&R function definitions/declarations (with no information about the function arguments)

[+] fuzztester|2 years ago|reply
>Remove K&R function definitions/declarations (with no information about the function arguments)

Not used C for many years, but used it a lot earlier.

And had read both the first and second editions of the k&r c book (ed. 1 pre-ansi, ed. 2 ansi).

based on that, iirc, this:

>Remove K&R function definitions / declarations

should actually be:

function definitions / declarations as in the first edition of the k&R C book.

[+] casey2|2 years ago|reply
What do you mean about the second one? In K&R functions are explained as

    name (argument list, if any)
    argument declarations, if any
    {
          declarations
          statements
    }
Is this disallowed in C23?
[+] TwentyPosts|2 years ago|reply
Wait, no trigraphs anymore???

This is horrible, I loved using `and` and `not` and `or` in C boolean expressions and to pretend I'm writing Python code. It's fun!

[+] AlectronikLabs|2 years ago|reply
Why don't they start to support units instead of these ugly header files to finally stop duplicating code? I see this might break stuff but you could implement it side by side with the preprocessor so old code would continue to work.
[+] Gibbon1|2 years ago|reply
Walter Bright says he was able to implement modules in C with 10 lines of code. That probably works with C but it'd make C incompatible with C++. Most people think that's reason enough not to do it. I think breaking compatibility with C++ would be like cutting the ropes to a sinking ship to save your own.
[+] flohofwoe|2 years ago|reply
Might not be a popular opinion, but I actually like that C headers only contain the public API declaration of a "module" while the implementation and private declarations live in a separate file. Makes it easy to figure out the public API just by reading the header and without having to sift through unimportant implementation code.

In other languages you need IDE support for extracting the public API of a module.

[+] j-krieger|2 years ago|reply
why not introduce an "import" keyword and keep the include keyword for old headers?
[+] malkia|2 years ago|reply
I hoped for defer (e.g. "RAII" of sorts), is there any way?
[+] LAC-Tech|2 years ago|reply
I remember back in the day everyone insisted C codebases had to be C89 so people could compile them in visual studio. EG the python interpreter. Is this still the case?
[+] pjmlp|2 years ago|reply
Visual C now does C17, minus the C99 features that became optional in C11 like VLAs.
[+] Karellen|2 years ago|reply
> If you have GCC 23 or LLVM (Clang) 16

gcc 23? That doesn't sound right

[+] matheusmoreira|2 years ago|reply
I'm told the C standards committee is actually just the C++ one. Explains a lot.
[+] dzonga|2 years ago|reply
quick qn ? for the tinkerers -- is there a language these days that nicely interfaces with c i.e able to use all c libraries through ffi. without loss of performance or extra fu.

the language being small enough that all basics can be grasped in a day.

the language being complete that it will remain the same in 10 years.

while at the same time being memory safe.

btw I don't think golang applies given the bad ffi story in go.

--- edit btw:: yeah this implies the use of a GC. though it must not have massive pauses or stop the world GC.

[+] oconnor663|2 years ago|reply
No there really isn't. The closest thing is "Rust after you've already gotten over the learning curve", but I realize that that learning curve is why you phrased your question the way you did.

Zig is aiming for what you're talking about, but it's not yet stable. They're interested in memory safety, but they don't want to add a borrow checker and they certainly don't want to add a GC, so my outsider guess is that they'll end up tolerating memory unsafety and trying to make up for that with debug modes and tooling. I don't really have a sense of what the end result will feel like, and the problems discussed in https://youtu.be/dEIsJPpCZYg make it sound like the basic semantics still have a ways to go.

Go could've been the language you're talking about if they'd given up on goroutines and just used the C stack, but goroutines are arguably the most important feature in the entire language, and it's not clear to me that there's a market for "Go but worse for network services and better for FFI". It would be hard to carve out a niche as a systems programming language that's great at making syscalls but can't realistically implement a syscall.

[+] andyjohnson0|2 years ago|reply
I've heard good things about Zig. Interop with C libraries seems to be good, and there is some degree of memory safety (though not, as i understand it, anything like .net/Java).
[+] lelanthran|2 years ago|reply
> quick qn ? for the tinkerers -- is there a language these days that nicely interfaces with c i.e able to use all c libraries through ffi.

Yes. https://ecl.common-lisp.dev/static/files/manual/current-manu...

> without loss of performance or extra fu.

Maybe a small loss, compared with fine-tuned C.

> the language being small enough that all basics can be grasped in a day.

The basics, certainly. You can learn the basics of Lisp syntax in about twenty minutes, the basics of looping, conditionals, datatype definitions, function definitions and all basic stuff in about a day.

> the language being complete that it will remain the same in 10 years.

Mostly, yes. ECL has mostly been the same for the previous 20 years. I see no reason that it would change substantially in the next 20.

> while at the same time being memory safe.

Caveats apply here, due to how deeply ECL can hook into C code. Even if you're doing weird things in the C code, it's unlikely you'd accidentally run into problems.

> btw I don't think golang applies given the bad ffi story in go.

What bad ffi story? I've never tried to use the FFI in go, but I haven't heard particularly bad things about it. Of course, that could be because most Go programmers aren't using the FFI anyway.

[+] akira2501|2 years ago|reply
> while at the same time being memory safe.

lua? luajit's got great ffi.

If you meant a compiled language then you can write code that is memory safe in C. You can even run tools against your code to measure this in various ways.

All "memory safe" languages that compile to lowest level ISA code are just memory safe "by default" and all of them necessarily offer escape hatches that turn it all off.

No "memory safe" compiled languages offers memory protections beyond what the operating system provides. If it's within the memory space of the process you can access it without limitation. "Memory safety" can reduce your exploit surface but it can't eliminate it out of an incorrectly designed program.

[+] flohofwoe|2 years ago|reply
> is there a language these days that nicely interfaces with c i.e able to use all c libraries through ffi

> the language being small enough that all basics can be grasped in a day.

That would be Zig. You can directly import C headers and compile C code with the Zig compiler and also cross-compile C code without requiring a separate compiler toolchain.

Currently it's also possible to compile C++ and ObjC (but not import C++ or ObjC headers), but that functionality will probably be delegated to a separate Clang toolchain in the future.

> the language being complete that it will remain the same in 10 years.

...that will take a while (also depending on whether you consider the stdlib part of the language or not).

> while at the same time being memory safe.

...that wouldn't be Zig then ;) (TBF, Zig is much stricter than C or C++, which helps to avoid some typical memory corruption problems in C or C++, but it's by far not as watertight as Rust when it comes to static memory safety - Zig does have a couple of runtime checks though, like array bounds checks - dangling pointers are still a problem though and are only caught at runtime via a special allocator.

[+] qznc|2 years ago|reply
Memory safe and easy implies a garbage collector to me. Unfortunately, garbage collection and C libraries easy to use is at odds.

In other words: Memory safe, easy to learn, easy C-FFI? Pick two.

[+] lolinder|2 years ago|reply
The instant that you have hassle-free FFI, it seems like you've given up on memory safety. Heck, just yesterday I got a segfault in a Python project because a library that I pulled in was just a wrapper for a faulty C module.

You can have all the memory safety in the world within the bounds of your own language, but it mostly gives you an illusion of security if the common pattern in the community is to just wrap C libraries. Having FFI be a bit of a hassle can actually go a long way towards shaping the community towards stronger memory safety.

[+] paulddraper|2 years ago|reply
D

[x] nicely interfaces with c

[x] the language being small enough that all basics can be grasped in a day

[x] the language being complete that it will remain the same in 10 years (the 1.0 release was 23 years ago)

[x] while at the same time being memory safe.

[+] adrusi|2 years ago|reply
while at the same time being memory safe.

memory safety doesn't mean just one thing, but probably it requires either a lot of rust-like features, a tracing garbage collector, or automatic reference counting.

the language being small enough that all basics can be grasped in a day

that disqualifies taking the rust-like path.

able to use all c libraries through ffi. without loss of performance or extra fu.

that disqualifies most (all?) advanced tracing gc strategies

it must not have massive pauses or stop the world GC.

that disqualifies simpler tracing gc strategies

depending on what precisely you're looking for, it's possible it might be a pipe dream. but it's also possible you'll find what you want in one of D, Nim or Swift. Swift is probably the closest to what you want on technical merit, but obviously extremely tied to Apple. D and Nim strap you with their particular flavor of tracing gc, which may or may not be suited to your needs.

[+] bitwize|2 years ago|reply
If you're willing to tolerate a GC, Gambit Scheme may be the closest. You can learn the basics of Scheme in a short time (but any programming language will take time to master). The C FFI is also pretty straightforward to use, but developing complete Scheme interfaces to large C libraries can get tedious.

Gambit is also reputed as the second fastest Scheme compiler out there; only Chez Scheme produces faster code.

[+] riku_iki|2 years ago|reply
Maybe rust if you ignore all the stuff you think looks complicated.
[+] mike_hock|2 years ago|reply
> typeof

What was wrong with "decltype"?

Seems utterly bizarre given that the rest is verbatim copypasta from C++, even the attribute syntax that sticks out like a sore thumb in C, and also given that auto and decl.. I mean, typeof, serve no useful purpose in C.

[+] parenthesis|2 years ago|reply
ckd_add(), ckd_sub() are ckd_mul() are what I'm looking forward to using.
[+] Arch-TK|2 years ago|reply
"slightly better" - nah, just as mediocre. Let me tell you, nobody stuck with C is going to bat an eyelid at this standard. They're going to continue using C89, or maybe C99 if they're lucky, for whatever reasons that justify it.

People who casually write C don't really care for C23 since it fixes all the wrong things. Nobody really wanted C+ (i.e. something slightly closer to C++ than before) which is basically all this standard achieves.

[+] flohofwoe|2 years ago|reply
I write a lot of C code (https://github.com/floooh/) and I'm actually looking forward to some of the changes in C23 (depending on when MSVC will implement them, because most of the changes I'm looking forward to already exist as non-standard language extension in GCC and Clang, but not in MSVC).
[+] JackSlateur|2 years ago|reply
Huh ? I use the cleanup attribute, for instance, which is a Real game changer

Nobody wants that ? Everybody who knows it exist wants that.

[+] mgaunard|2 years ago|reply
C++ is already a better C.

So much so that new revisions of C are just backporting features at this point.