IMHO if you can't write C code then you can't program. Everything else is just compiler semantics.
That's a black-n-white sweeping statement that's very common to see among engineers who tends to think in absolutes. The truth is far more nuanced though, since it depends on what you need to do; don't tear down your garrage with a box-cutter and don't open your packages with a circular saw. Pick the right tool for the job!
Some of the worst code I've read over the years, are by embedded engineers who are so stuck in their old bit-twiddling C world that they lack all other elements of what I would consider to be professional software construction (i.e. no logging, no unit tests, homemade data structures use rather than tried-n-tested library versions, inability to make the code easy to read, silly optimizations which the compiler can do better etc.). When we write software today, we're writing as much to our colleagues as we are writing to the compiler, and C is just not very good at expressing intent (i.e. no type-safety, const can be cast away etc.).
I understand what you mean, C as a (very lightweight) abstraction fits well in the embedded and systems world, with strong ties to fundamental CS topics such as Turing machines etc. However, as program complexity and size increases, you quickly run out of abstractions. Sure you can roll your own VTABLE to achive polomorfism and mark-and-sweep to get garbage collection in parts of your system, but that makes you more of a fool than anything else - people smarter than you already came up with these abstractions in a cohesive language.
The latest iteration of polyglot language hybrids like Scala, Go, Clojure and even C# attack the concurrency behemoth head-on, something that will always remain a nightmare to do in C. At the end of the day, you'll want to make software that solves your problem rather than spending your time hunting down memory leaks and deadlocks.