I'll assert that a majority of C programmers do not understand unsigned types and misuse them.
It's quite common to end up needing to use both signed and unsigned types in the same expression and to end up invoking undefined behaviour trying to protect yourself. C overflow semantics (i.e. undefined) in particular.
Signed types should be the default, and overflow should be defined as wrapping two's complement. There's very good reasons why C# and Java chose these defaults.
The places where unsigned numbers are justified are incredibly rare: bitwise operations, and working with >2GB heap sizes on 32-bit machines. That's about it. In almost every other circumstance, using a signed type (the next size up if the range is inadequate) is better.
Especially pernicious is using something like size_t for things like container entry counts. It's very common to add and subtract with container counts, and very easy to end up inadvertently wrapping or mixing with signed types in common container algorithms.
PS: my experience was deeply coloured while working on the Delphi RTL, making it overflow safe. It was not trivial.
PPS: it was revealing that the comments on the article arguing in favour of unsigned types repeatedly made programming errors and invoked undefined behaviour. That's because unsigned types are misunderstood and misused.