First thing first, the tutorials use void main
. The comp.lang.c
frequently asked question 11.15 should be of interest when assessing the quality of the tutorial:
Q: The book I've been using, C Programing for the Compleat Idiot, always uses void main()
.
A: Perhaps its author counts himself among the target audience. Many books unaccountably use void main()
in examples, and assert that it's correct. They're wrong, or they're assuming that everyone writes code for systems where it happens to work.
That said, the rest of the example is ill-advised. The C standard does not define the behaviour of signed left shift. However, a compiler implementation is allowed to define behaviour for those cases that the standard leaves purposefully open. For example GCC does define that
- all signed integers have two's-complement format
<<
is well-defined on negative signed numbers and >>
works as if by sign extension.
Hence, -1 << 4
on GCC is guaranteed to result in -16
; the bit representation of these numbers, given 32 bit int
are 1111 1111 1111 1111 1111 1111 1111 1111
and 1111 1111 1111 1111 1111 1111 1111 0000
respectively.
Now, there is another undefined behaviour here: %x
expects an argument that is an unsigned int
, however you're passing in a signed int
, with a value that is not representable in an unsigned int
. However, the behaviour on GCC / with common libc's most probably is that the bytes of the signed integer are interpreted as an unsigned integer, 1111 1111 1111 1111 1111 1111 1111 0000
in binary, which in hex is FFFFFFF0
.
However, a portable C program should really never
- assume two's complement representation - when the representation is of importance, use
unsigned int
or even uint32_t
- assume that the
<<
or >>
on negative numbers have a certain behaviour
- use
%x
with signed numbers
- write
void main
.
A portable (C99, C11, C17) program for the same use case, with defined behaviour, would be
#include <stdio.h>
#include <inttypes.h>
int main(void)
{
printf("%" PRIx32, (uint32_t)-1 << 4);
}