Hacker News new | ask | show | jobs
by acuozzo 1301 days 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!

2 comments

Atomic 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)#Opti...

<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.

> 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

Requiring C11 is itself a portability issue.

I can easily whip up CAS for all platforms I care about, plus a few more for bonus, using nothing but C99 or C90 (and have actually done it before).

Possibly, without even using any language extensions, unless I want the operations inlined.

Did you manage to write a truly portable compare-and-swap in standard C? Or did the code just happen to seem to work on your platform?

I'd be surprised if the former were possible. From a quick web search, C doesn't even give you the guarantees necessary for Peterson's Algorithm, [0][1] and volatile doesn't help. [2][3]

[0] https://codereview.stackexchange.com/a/124683

[1] https://stackoverflow.com/questions/35527557/errors-with-pet...

[2] https://web.archive.org/web/20160525000152/https://software....

[3] https://old.reddit.com/r/programming/comments/d457c/volatile...

I think the point by kazinator still stands. C11 is still a portability issue (which was the root of my original question above). ANSI C is the de-facto baseline everything has in common, using C11+ narrows which platforms you're able to build for. Even if C11 does provide the primitives for correct implementation of Peterson's Algorithm, what about the other platforms that don't have a C11 compiler - it does them no good. As to the point more directly, a lot of the C code I've seen is for real time and embedded systems that are usually time and memory partitioned, and do not have the same concerns regarding concurrency.

I guess if I could rephrase my original question: People who are going to adopt C23 - who are you and what field/industry/line-of-work are you in?

Asking because in my line-of-work, C is ubiquitous and I personally love coding in C, but anything beyond ANSI C (or C99) is "cool" but undermines the point of C as I've used it, which is its use cross-platform for a huge set of common and uncommon architectures and instruction sets. If something only needs to run on common, conventional platforms, C, however much I love it, would no longer necessarily be a strong contender in light of many alternatives. It seems like these standards target an ever shrinking audience (much smaller than the whole universe of software developers working in C).

  > ANSI C is the de-facto baseline everything has in common,
  > using C11+ narrows which platforms you're able to build for.
Sure, but which platforms are you thinking of? I think you're overestimating the proportion of C codebases that care about targeting highly exotic hardware platforms. GCC can target all sorts of ISAs, including embedded platforms. It can't target, say, the 6502, or PIC, or Z80, but they're small niches.

I'm not an embedded software developer though, perhaps there are more developers using niche C compilers than I realise.

  > Even if C11 does provide the primitives for correct implementation
  > of Peterson's Algorithm, what about the other platforms that don't
  > have a C11 compiler - it does them no good.
If portable atomics/synchronisation machinery is not offered by your C compiler or its libraries, I figure your options are:

1. Use platform-specific atomics/synchronisation functionality

2. Leverage compiler-specific guarantees to write platform-specific atomics/synchronisation functionality, if your compiler offers such guarantees

3. Write your atomics/synchronisation functionality in assembly, and call it from C

Here's a project that uses all 3 approaches. [0] (It's old-school C++ rather than C, but it's the same in principle.)

I'm fairly sure it's not possible to implement your own portable synchronisation primitives in standard-compliant C90 code. As I understand it, the C90 standard has nothing at all to say on concurrency. It's possible that such an attempt might happen to work, on some given platform, but it would be 'correct by coincidence', rather than by definition. (Again, unless the particular compiler guaranteed the necessary properties.)

[0] https://github.com/gogglesguy/fox/blob/fe99324/lib/FXAtomic....

Neither. The code wasn't standard C, and it didn't just "happen" to work, either.

You probably wouldn't want to build an atomic compare-exchange in standard C, even if it were possible; you find out what the hardware provides and work with that.

  > The code wasn't standard C, and it didn't just "happen" to work
Thanks, that makes sense.

At the risk of sounding pedantic, you did say using nothing but C99 or C90, implying use of standard features only.

  > You probably wouldn't want to build an atomic compare-exchange in
  > standard C, even if it were possible; you find out what the
  > hardware provides and work with that.
Agreed.
Right; I could do it using nothing but standard C features in C source files, by defining some C compatible assembly language routines. The compare_swap primitive can be an external function, e.g.:

  bool cmpswap64(uint64_t *location, uint64_t if_old, uint64_t then_new);
Code that relies on the header doesn't have to process anything compiler-specific. FFI could be used to bind to that function from non-C languages.
Interesting discussion, lots of good points all around. Thanks to you both.