I had to check this because my intuition told me that this would generate a warning. GCC and Clang both warn about that assignment with -Wsign-conversion, however that doesn't seem to be enabled with any of -Wall, -Wextra, or -Wpendatic and only clang's -Weverthing would catch it if you weren't specifically looking for it.
that's because assigning -1 to an unsigned number is an idiomatic, safe and portable way to setting all bits to 1. You could argue that an explicit cast should be warranted in this case, and I sort of agree, but it would break way too much code.
C implicitly converts integer types as needed. The specific conversion rules are rather convoluted, see section 6.3 of the ISO C standard for the details. Before C23 this was implementation defined, but since C23 now mandates two's complement representation of signed integers and wrapping for unsigned overflow (as before) the `-1` is converted to UINT_MAX. Then the `%d` format specifier performs a conversion from `unsigned int` back to `int` for printing, resulting in `-1`. Implicit conversions between types of the same rank are guaranteed to "round-trip", you get back the value you started with when converting back to the starting type. If they'd specified an unsigned format specifier for printing then they wouldn't get `-1` printed.
I'm pretty sure that this was well defined and portable well before C23. Although the representation was implementation defined, IIRC signed to unsigned has always been guaranteed to be as-if in two-complement.
You're probably correct, but I didn't have the earlier standards as quickly to hand to cite. The storage representation being twos complement is new, I didn't mean to imply that the conversion was as well.
The -1 here is hiding the fact that -1 is really just 0xffffffff due to two's complement (architecture dependant of course)
And printing it as %d is technically a misuse of printf, since %d means print as a signed integer. If you did %u (print as unsigned integer) instead you'd see the value is really 4,294,967,295 (again, platform dependant)
Hah yes, me too. Python has the opposite problem. C changes the type of a supplied value to fit the declared variable type. Python changes the type of the variable to fit its value's (or reference's) type.
So in C if I assign a char literal to an int, I get an int. If I do the same in Python, I get a string.
In a strongly typed language, which I'm defining as "needs the left and right hand side of an assignment expression to match somehow", I'd get a type error.