Live data from Hacker News

Giving C a superpower: custom header file (safe_c.h)

hwisnu.bearblog.dev

111–120 of 277 posts

Re: Giving C a superpower: custom header file (safe_c.h)

#112

Earlier quoted context omitted.

> very exotic requirements I'd be interested to know what you are thinking. The primary exotic thing I can imagine is an architecture lacking the ability to do atomic operations. But even in that case, C11 has atomic operations [1] built in. So worst case, the C library for the target architecture would likely boil down to mutex operations. [1] https://en.cppreference.com/w/c/atomic.html

Which platforms might that be? Even MIPS has atomics (at least pointer sized last i checked).

AFIAK, and I'm not MIPS expert, but I believe it doesn't have the ability to add a value directly to a memory address. You have to do something like

    // Not real MIPS, just what I've gleaned from a brief look at some docs
    LOAD addr, register
    ADD 1, register
    STORE register, addr
The LOAD and STORE are atomic, but the `ADD` happens out of band.

That's a problem if any sort of interrupt happens (if you are multi-threading then a possibility). If it happens at the load, then a separate thread can update "addr" which mean the later STORE will stomp on what's there.

x86 and ARM can do

    ADD 1, addr
as well as other instructions like "compare and swap"

    LOAD addr, register
    MOV register, register2
    ADD 1, register2
    COMPARE_AND_SWAP addr, register, register2
    if (cas_failed) { try again }

Re: Giving C a superpower: custom header file (safe_c.h)

#113
post #77
post #35

Earlier quoted context omitted.

Why would I want to run a garbage collector and deal with it's performance penalties?

IDK about Fil-C, but in Java garbage collector actually speeds up memory management compared to C++ if you measure the throughput. The cost of this is increased worst-case latency. A CLI tool (which most POSIX tools are) would pick throughput over latency any time.

Java (w/ the JIT warmed up) could possibly be faster than C++, if the C++ program were to allocate every single value on the heap.

But you're never going to encounter a C++ program that does that, since it makes no sense.

Re: Giving C a superpower: custom header file (safe_c.h)

#115

Intentionally or not, this post demonstrates one of the things that makes safer abstractions in C less desirable: the shared pointer implementation uses a POSIX mutex, which means it’s (1) not cross platform, and (2) pays the mutex overhead even in provably single-threaded contexts. In other words, it’s not a zero-cost abstraction. C++’s shared pointer has the same problem; Rust avoids it by having two types (Rc and…

> Intentionally or not, this post demonstrates one of the things that makes safer abstractions in C less desirable: the shared pointer implementation uses a POSIX mutex, which means it’s (1) not cross platform, and (2) pays the mutex overhead even in provably single-threaded contexts. In other words, it’s not a zero-cost abstraction.

It's an implementation detail. They could have used atomic load/store (since c11) to implement the increment/decrement.

TBH I'm not sure what a mutex buys you in this situation (reference counting)

Re: Giving C a superpower: custom header file (safe_c.h)

#116
post #82

Nice, but if the intention is portability my experience has unfortunately been that you pretty much have to stick to C99. MSVC’s C compiler is rough, but pretty much necessary for actual cross platform. I have my own such header which has many, many things like the OP’s. As much as I would find it constantly useful, I don’t have a cleanup utility because of this. But if you can stay out of MSVC world, awesome! You ca…

You can use GCC on MS Windows just fine. Installing MSYS2 will also give you a package manager.

Yes, of course. Unfortunately, sometimes you need to link to Windows binaries and therefore need to compile against the Windows ABI.

Re: Giving C a superpower: custom header file (safe_c.h)

#117

Intentionally or not, this post demonstrates one of the things that makes safer abstractions in C less desirable: the shared pointer implementation uses a POSIX mutex, which means it’s (1) not cross platform, and (2) pays the mutex overhead even in provably single-threaded contexts. In other words, it’s not a zero-cost abstraction. C++’s shared pointer has the same problem; Rust avoids it by having two types (Rc and…

The number of times I might want to write something in C and have it less likely to crash absolutely dwarfs the number of times I care about that code being cross-platform. Sure, cross-platform is desirable, if there's no cost involved, and mandatory if you actually need it, but it's a "nice to have" most of the time, not a "needs this". As for mutex overheads, yep, that's annoying, but really, how annoying ? Modern…

> As for mutex overheads, yep, that's annoying, but really, how annoying ?

For this use-case, you might not notice. ISTR, when examing the pthreads source code for some platform, that mutexes only do a context switch as a fallback, if the lock cannot be acquired.

So, for most use-cases of this header, you should not see any performance impact. You'll see some bloat, to be sure.

Re: Giving C a superpower: custom header file (safe_c.h)

#118

Earlier quoted context omitted.

Well, basically, yeah, if your platform lacks support for atomics, or if you'd need some extra functionality around the shared pointer like e.g. logging the shared pointer refcounts while enforcing consistent ordering of logs (which can be useful if you're unfortunate enough to have to debug a race condition where you need to pay attention to refcounts, assuming the extra mutex won't make your heisenbug disappear), o…

Does there exist any platform which has multithreading but not atomics? Such a platform would be quite impractical as you can't really implement locks or any other threading primitive without atomics.

Certainly such systems can pretty readily exist. You merely need atomic reads/writes in order to implement locks.

You can't create userspace locks which is a bummer, but the OS has the capability of enforcing locks. That's basically how early locking worked.

The main thing needed to make a correct lock is interrupt protection. Something every OS has.

To go fast, you need atomic operations. It especially becomes important if you are dealing with multiple cores. However, for a single core system atomics aren't needed for the OS to create locks.

Re: Giving C a superpower: custom header file (safe_c.h)

#119
post #68

Earlier quoted context omitted.

Yes, plenty have been done already so since Lisp Machines, Smalltalk, Interlisp-D, Cedar, Oberon, Sing#, Modula-2+, Modula-3, D, Swift,.... It is a matter to have an open mindset. Eventually system languages with manual memory management will be done history in agentic driven OSes.

Swift, by design, does not have GC.

RC is a GC method and the least efficient one.

Re: Giving C a superpower: custom header file (safe_c.h)

#120

Earlier quoted context omitted.

I consider code written in Frama-C as a verifiable C dialect, like SPARK is to Ada, rather than C proper. I find it funny how standard C is an undefined-behaviour minefield with few redeeming qualities, but it gets some of the best formal verification tools around.

The popular C compilers include a static analyzer and a runtime sanitizer. What features do you consider proper C? The C standard has always been about standardization of existing compilers, not about prescribing features.

By "static analysis" you mean unsound, best-effort analyzers which try to study code as-is, rarely allow extra annotations, and tolerate false negatives and even positives by design.

While these are a huge improvement over no extra tooling, they don't compare to analyzers like Frama-C plugins, which demand further annotations/proofs if necessary to show code is free of UB, and you can provide further to show your code is not just safe, but correct. Assuming one doesn't ship rejected code, the latter is pretty much its own language with much stronger guarantees, much like SPARK is to Ada.

I like sanitizers and other compiler-specific guarantees, they at least try to fill the gaps by giving proper semantics to UB. But the ones available for C are still insufficient, and some are very resource-heavy compared to just running safe code. I'm excited about Fil-C showing a path forward here.

Post reply on HN