C looks friendly enough, but it has many nooks and crannies filled with undefined behavior (UB). If your program accidentally does something like overflow a signed integer, you're toast.
Raymond Chen has the best write up on UB that I've seen: <https://devblogs.microsoft.com/oldnewthing/20140627-00/?p=63...>.
In addition to the "obvious" undefined behavior, strict aliasing is subtle and poorly understood in my experience. Consider the following:
Foo ReadFooFromBytes(const char* data, size_t len) {
Foo foo;
assert(len == sizeof(Foo));
foo = *(const Foo*)(data);
return foo;
}
Foo ConvertToFoo(Bar bar) {
return ReadFromBytes((const char*)&bar, sizeof(bar));
}
The `ReadFooFromBytes()` function could exhibit undefined behavior, depending on the
provenance of its pointer parameter.
If you gave it a pointer to a true array of chars, it's fine. If you use `ConvertToFoo()`, big bada boom. Truly baffling stuff, the first time you encounter it.