The "container"/"offsetof" problem is strange. If you only have a pointer to a member of a struct, you don't really know the type of the containing struct. You don't even know if there is a containing struct. "offsetof" implies an unchecked cast, violating type checking. Why is that used anywhere, let alone in the Linux kernel? (In decades of C/C++ programming, I never wanted to do that.)
This is why I really hope Rust can replace C. (As I write occasionally, "Rust guys, please don't screw it up".) Rust is complicated, but it's simpler than the semantics of C undefined behavior. That may be the answer to use on C programmers who think Rust is too complicated. All those little issues in C, such as "can you dereference the element one past the end of the array" and "after dereferencing, what happens if you then test for a null pointer" require a good understanding of the machine model and how an optimizing compiler works.