Wouldn't a better first question be _why_ we're teaching students C?
One answer might be that although students might spend most of their later professional lives in higher-level languages, they should have some experience in a low-level language.
The ideal such language would not have memory management (i.e., not Java / Python), no memory management help from the type system (so no Rust), and no fancy facilities to build abstractions (so no Rust or C++). This language should, ideally, still be a little more pleasant to work with than assembly (so, no assembly). For historical reasons, we would still like unchecked array accesses and null-terminated strings.
Now C is an answer to this question, but it need not be the only answer. We could instead teach students a fictionalized version of real C. So nice 2-s complement behavior on overflows, buffer overflows segfaults and other bad behavior, but mostly of the predictable kind. We could define undefined behaviors as the instructor sees fit.
As much as we can, we can try to make this fictionalized language agree with the semantics of gcc -O0. We can then study gcc -O0 -S itself as an empirical artifact, and use it to understand x86/x86-64/ARM/MIPS assembly.
Finally, while we're at it, we can use the Bourbaki dangerous bend symbol (https://en.wikipedia.org/wiki/Bourbaki_dangerous_bend_symbol) to repeatedly remind students that what they're studying isn't a real language, that real C has sharp edges (including undefined behaviors), and that things like ASAN / Valgrind / ... exist.
I worry that this article is confusing that we'd like students to eventually understand (some understanding of C and an appreciation of the fact that it is an important language which still needs to be handled with care) with the didactic process of reaching that understanding. Wittgenstein's ladder is a thing.
If we went to the trouble of making a safe version of C - and we would have to actually implement it; you can't very well teach students to program without letting them actually compile the code and run it - I'd rather just... use that. Call it C24, get it into GCC and Clang, and standardize on something with less Undefined Behavior and painful sharp edges.
I feel like you're trying to merge computation as a science with an idealized language choice and I don't think it would serve students well.
The "sharp edges" of C in either user mode or kernel mode when running on an x86 or arm platform are true implementation semantics that you must deal with while trying to realize genuine "computation."
Programming languages are just collections of human shorthand for managing these semantics. Which makes me feel that inventing this language would be putting the cart before the horse.
One answer might be that although students might spend most of their later professional lives in higher-level languages, they should have some experience in a low-level language.
The ideal such language would not have memory management (i.e., not Java / Python), no memory management help from the type system (so no Rust), and no fancy facilities to build abstractions (so no Rust or C++). This language should, ideally, still be a little more pleasant to work with than assembly (so, no assembly). For historical reasons, we would still like unchecked array accesses and null-terminated strings.
Now C is an answer to this question, but it need not be the only answer. We could instead teach students a fictionalized version of real C. So nice 2-s complement behavior on overflows, buffer overflows segfaults and other bad behavior, but mostly of the predictable kind. We could define undefined behaviors as the instructor sees fit.
As much as we can, we can try to make this fictionalized language agree with the semantics of gcc -O0. We can then study gcc -O0 -S itself as an empirical artifact, and use it to understand x86/x86-64/ARM/MIPS assembly.
Finally, while we're at it, we can use the Bourbaki dangerous bend symbol (https://en.wikipedia.org/wiki/Bourbaki_dangerous_bend_symbol) to repeatedly remind students that what they're studying isn't a real language, that real C has sharp edges (including undefined behaviors), and that things like ASAN / Valgrind / ... exist.
I worry that this article is confusing that we'd like students to eventually understand (some understanding of C and an appreciation of the fact that it is an important language which still needs to be handled with care) with the didactic process of reaching that understanding. Wittgenstein's ladder is a thing.