by palata | 2025-07-05 11:06:53+00:00
> there's a compiler for every conceivable CPU ever made

This is not specific to C++, that's just how computers work.

I think it's important to understand that at the lowest level, different hardware works differently. A bit like if you take the pedals from your car and put them on your bike, your bike won't suddenly accelerate when you press the gas pedal. For instance, different CPU architectures have different sets of instructions; machine code compiled for one just doesn't fit in the other.

The programming language is an abstraction. You can write code in C (which can be seen as a standardised set of instructions, I guess) and "compile" it for the CPU architecture you want. The "compiler" is the thing that understands C and translates it to machine code. It is an abstraction itself: you could write the machine code (the bits) manually, but it's easier to write C. The abstraction is here to make it "easier", but it's usually not perfect. When you need very very high performance, it's not uncommon to look at the assembly level.

So yeah, if you want to compile for ARM, you need a compiler that knows how to translate your C into the ARM set of instructions. Now there are "families" of architectures, I guess that's what you mean by "groupings"? Say you build parts for cars. If you build pedals that fit in one car model A, they won't necessarily fit in car model B. But there can be variants of car A: automatic or manual. They have different sets of pedals: the manual one has a clutch pedal that does not exist in automatic. If you build the whole set of pedals for car model A, you have to know about that and provide a set for the automatic flavour and another set for the manual flavour. But if you only build gas pedals, you don't have to care: all the flavours of A have the same gas pedal. Some CPUs share a lot of instructions, but not all of them. Maybe there is a flavour of CPU that provides new instructions that are more efficient for some computations. If you don't care about performance, you can just use the "basic set of instructions", but if you actually want to leverage those efficient instructions specific to that particular CPU... well you have to use a compiler that knows about them.

In C/C++, you can't "make this for all computers". It's not possible to make one binary that works everywhere, just because there are very different systems (be it different CPU architectures, but also just the file format between Windows and Linux for instance). But there are ways to abstract that, for instance that's what the JVM does. Instead of compiling your Java (or Kotlin, Scala, etc) to machine code, your compiler compiles it to JVM bytecode. That's an abstraction again. Bytecode is just code that the JVM can run with. And this "works everywhere" in the sense that "it works as long as you have a JVM that can run it". But there are tons of different JVM binaries, because you can't just make one that runs everywhere. It's just that someone built a JVM for your machine, so that now you can run any JVM program on it. But the JVM itself is very much not portable.

It's all about abstraction. If you work in Javascript or Python, you may never have to know about anything that's happening below, because you live in your nice abstraction level. But as soon as you want to compile a native binary, you have to go down the abstraction layers and start understanding more of what's happening. It's not a C++ problem: you can compile Kotlin code to a native binary and you'll have the same problems. Same for any language that compiles to a native binary.

> I get angry at things that are obviously more confusing than they need to be.

Are they obviously more confusing than they need to be, or is the world just more complicated than one might expect? Computer are extremely complex machines. If something is easy, that's because you're staying at a comfortable abstraction level (with all the limitations that come with it).

I hope this helps.