Much of the existing C code out there is filled with these things because they weren't errors until recently, and people ignore warnings. This is why Fedora and Gentoo are doing so much work to port all of their software to "modern C", so that it will actually compile with new compilers, and hopefully fix bugs at the same time. Existing c++ code did not have this problem because it was always an error.
Note that modern compiler in this case means bleeding edge, released literally within weeks or months of this posts date, most distros are not yet compiling the world with these and most users are not using them.
https://fedoraproject.org/wiki/Changes/PortingToModernC https://wiki.gentoo.org/wiki/Modern_C_porting
>Passing void* around is also generally not necessary in C.
This is not true.
I know several examples in real libraries that require this, two OTTOMH is PAM and Wayland. Both of these require void pointers to give you access to some state object that you create and need passed around, it has no way to know what this type will be ahead of time, and C has no other way to do this.
Another example is data structures or algorithms on data structures like sorting, you either use macros to emulate generics or you use void pointers. Qsort is a perfect example.
>One can take the address of an array and then get the same type checking.
I don't think this is true, C will not include the length in the type. Passing std::array<T, N> in C++ causes an error if T or N are different, in C this length information is not part of the type and does not get type checked.