C has often been described as a "high level assembly language". Though awkwardly it specifies so little about the actual machine that you couldn't well USE it as anything like a portable assembly language!
How many bits per char? Well..
How many bits per short..? int? ...long? long long?
How many bits per float? ... double?
Is the FP on this target SW or HW, IEEE-754 compatible or something totally other?
How are signed integers represented? Two's complement? One's complement? Sign magnitude?
How do you do things like arithmetic shifts / rotates involving signed quantities?
How about standard efficient portable bit-reverse, count leading / trailing zeroes?, count number of 1s in a word? Calculate parity? Set / Clear a bit at index?
Can you load a multi-byte type from an unaligned address? If so under which cases? Is it efficient?
What about structure padding / packing?
Are pointers to different types convertible to each other?
Pointer comparison and arithmetic valid / invalid cases?
What's this NULL pointer thing anyway -- 0 is a valid address sometimes!
Macros / preprocessor stuff that doesn't kind of suck?
Taking advantage of linker / assembler capabilities by a standard higher level "C" interface?
How do you even do something SUPER SIMPLE like detect flags relating to arithmetic / logical operations -- was there a carry? Is the result 0? positive? negative? NaN? Inf? Denormalized?
What about swizzling? Byte swapping? Endian conversion?
What about atomic operations on bits, bytes, fundamental data types?
Locks? Semaphores? Mutexes?
You interpret the description backwards.
It's not that C has every feature in every assembly language.
It's that every feature in C maps efficiently to pretty much any sane ISA.
C assumes and acknowledges that from time to time you'll need to link in an assembly language routine, or use some inline asm.
How big are char, short, int, long? The same size as in the target ISA.
How are signed integers represented? The same as on the target ISA.
How do shifts involving signed quantities behave? The same as on the target ISA.
Can you load a multi-byte type from an unaligned address? If and only if the target ISA can.
You have to know all that stuff anyway if you program in assembly language. C doesn't add to that. C just frees you from having to do detailed instruction selection and register allocation and managing temporary values.
If you *need* integers of a known size then you can specify those with uint8_t, int_least32_t and friends. If you want an integer that a pointer can be converted to and from without loss you have uintptr_t. And so on. I don't know of any other language that allows you to express your actual needs so precisely. Maybe Ada?
Rotates? Bit reverse? CLZ? Popcount? Parity? Set/Clear a bit at an index? Plenty of ISAs don't have some or all of those. If C provided those as built-ins then you'd probably assume they were as efficient as an add though they're not. Better to make you aware some of those are going to require a dozen or two instructions.
"something SUPER SIMPLE like detect flags relating to arithmetic / logical operations" -- the majority of microcontroller and Linux boards I have in this house DON'T HAVE FLAGS.