It's an ABI, there have to be one, and C was the de-facto system programming language.
I don't get the complaint, there are flaws, it could have been much MUCH worse.
It's an ABI, there have to be one, and C was the de-facto system programming language.
I don't get the complaint, there are flaws, it could have been much MUCH worse.
C is also a terrible language to define an ABI because, by design, it's very imprecise in the way that it defines types.
C was never the only systems language.
It's perfectly precise, particularly if you choose to use <stdint.h> which has been available in the language for a very long time. You may have some issues with specific types and platform variability, but it's absurd to cast this as "it's imprecise with types."
It's _flexible_ with types.
People seem to miss that this is the reason why C is the lingua franca. It isn't trying to "perfect" computing. It just makes it possible. There's a lesson for new languages here.
This is why C is mostly portable with minimum effort unless you do hardware specific things, or use the variable to their limits. In that case you can always define fixed size types.
I don't get why people love to bash C. No language has an obligation to do please the programmer in its default modus operandi. Programming languages exist to interface hardware with humans, and C operates in the realm of the hardware, and that's perfectly OK for me.
C ABIs (of which there are many because the C standard doesn’t cover ABI) are full of legacy cruft, because they need to be stable and backwards-compatible more than they need to be sensible or efficient.
The C ABI can even vary depending on compiler flags, e.g. availability of AVX affects calling conventions. It’s not easy to be interoperable with this, especially when ABI-affecting compiler flags and macros may be set by an arbitrary build system, not even the C source code.
Android userspace uses Java and can only talk to native code via JNI, which definitely isn't a C ABI.
Likewise there isn't any writing to metal on ChromeOS for the official userspace APIs, running Linux (Crostini) implies running a sandboxed version on top of the actual ChromeOS, while Android on ChromeOS not only has the same JNI restrictions, it also is sandboxed without access to host OS.
EDIT: I also forgot that ChromeOS and Android expose many of their key APIs to native code via OS IPC, on top of the constraints mentioned above. With endpoints written in a mix of C++, Java and now Rust.
You don't do OS syscalls via JNI, rather marshal representation of Java objects for consuptiom from native languages.
JNI is an API between the JVM and C- or C++-coded plugins that can implement native methods. "Native method" means "written in C (or C++)". There's a) a standard interface that C-coded methods must present (depending on their Java signature) and b) a set of utility C functions provided by the JVM.
Because these plugins are loaded via `dlopen()`/`LoadLibrary_Ex()`/etc. the JNI API has an ABI.
If you don't believe me go look it up. There's a ton of resources on JNI. Here's an example taken from the wikipedia page on JNI:
extern "C"
JNIEXPORT void JNICALL Java_ClassName_MethodName
(JNIEnv *env, jobject obj, jstring javaString)
{
const char *nativeString = env->GetStringUTFChars(javaString, 0);
//Do something with the nativeString
env->ReleaseStringUTFChars(javaString, nativeString);
}Then dive into Vax/VMS with Bliss, Multics with PL/I and plenty of others that lost to UNIX.
Loosely defined, most embedded Forth systems act as an OS and they tend to use the system's assembly or the Forth system itself as the ABI.
PC-DOS derivatives obviously use x86 registers and interrupts as an ABI - that's more assembly and machine language oriented than C.
Even with these restrictions in place, modern register-based calling conventions can be still be rather complex, but these restrictions reduce it somewhat. They help to avoid areas in which implementations traditionally diverge, too.
The bits of C that need to be avoided in APIs are:
- bitfields unless no bitfield crosses a
byte boundary
- struct fields of enum types (because the
size of the enum type is implementation
specific)
The spec should fix this, damnit.The one thing that could be improved is to come up with a better language than C headers to specify cross-language APIs/ABIs.
The fact that different ABIs exist cannot be helped. That’s something one has to cope with in any case, independently of C.
One way to sidestep many of the issues is to target the JVM. ;)
If C is such a problem id like to see some alternatives which offer what C does but less painfully.
C is only useful in certain domains, but within the domains where C is really good, theres no others. (unless you want to go assembly mode... good luck :) can be fun)..
anyhting that is less painful, exposes less complexity and is usually therefore less generally applicable.
A lot of the pains of C are lack of understanding how to use it because using it requires deep knowledge of it, and the target platform.
that being said, i do get userland applications and C dont really mix anymore. that is a fair point imho.
Among type issues, it also has the infamous "Macros" that are really just unanalyzable text replacements.
I find it amusing that after half a century of existence and powering the world's IT infrastructure, suddenly some illuminated individual felt entitled to claim they alone found problems that they alone can fix.