I’m actually of the opinion that C should be taught hand in hand or just after someone learns assembly. It’s admittedly a bit gatekeeper-y, but IMHO C should be thought of with same mindset as you would develop an ASM program, but with a bunch of shortcuts and syntactic sugar.
Without understanding what code gets generated, there are so many footguns it can be dangerous at best. Knowing things like calling conventions and how the compiler interacts with memory are really important.
I agree. I learned this way, and, for example, wrapping my head around pointers was much easier after I already understood why LEA existed. Yes, C isn't portable assembler, and no, you can't necessarily predict what ASM will be produced from a particular snippet of code. However, C operates closer to "portable assembler" than any other programming language, and it's a lot harder to go from anything else to C than it is to go from assembly to C
I'm of the opposite opinion. The portable-assembler camp is responsible for a lot of the issues and footguns, because they think they know what code will be generated. But they don't. Compilers can generate any code they want, as long as the program ends up doing the correct io and side effects.
The assembler perspective is important, but not for correctness, rather for optimization. When you optimize it starts mattering how much register pressure and cache pressure etc you have.
I do resonate with your comment a lot, but the portable assembly aspect also drove much of the current C use. As a compromise we may teach two quite different architectures and ask students to write a single code that runs in both. This way they can avoid false beliefs like `sizeof(int) == 4` and hopefully still learn common aspects of most architectures that shaped C's design.
I'm not saying because they need to understand exactly what code gets generated, compiler optimizations can produce interesting results. What I am saying is the idea that an if statement from an assembly is a compare and a jump... knowing what happens under the hood is kind of important for people writing C in 2024.
Like I guess the point I have to make is that if you are writing C in 2024, there is likely a good reason, and if you don't know what's going on in the assembler, I feel like people are playing with fire.
I think that's the misleading perspective the grandparent comment is referring to. An if statement in C isn't necessarily a branch. The generated assembly assembly might have no branches if it's eliminated, it might have multiple branches, and the compiler might even include a function call (e.g. fharden-conditional-branches). You can't know just by looking at the source code alone.
I've found that I'm much less accurate when writing code for non-GCC/Clang compilers because my mental model of what's going to be generated isn't accurate enough without the years of experience I've had looking at the outputs of those specific compiler families.
While true, compared to some of the other languages C code is still relatively close to source, e.g. it will not completely change your data types behind your back etc.
Without understanding what code gets generated, there are so many footguns it can be dangerous at best. Knowing things like calling conventions and how the compiler interacts with memory are really important.