5 Mildly Interesting Facts About CPublished on the
I learned C during the summer term of my first year at Imperial. In this post, I’m going to talk about five rather minor details I’ve picked up about C. I don’t think these will ever be useful when actually programming, but they’re interesting to know.
Returning in Main
In C99 and C11, you don’t actually need a
return statement in your
main function. This is as, the specification declares that if the end of the function is reached without a
return, this is treated the same as the function returning 0.
Reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspeciﬁed.
However, this is not the case in the C89 specification, where an explicit
return is required. Note returning the value 0, always means success. Alternatively, you can also return
EXIT_SUCCESS which is defined in
stdlib.h, which equals 0 on most systems and also means success. This lets you avoid magic numbers.
You probably know that C lets you perform bitwise operations, e.g.
& for bitwise AND,
| for bitwise OR and
^ for bitwise XOR. What you might not know is that these bitwise operators have a lower precedence than
!= and other comparison operatos. This means an expression such as
a & b == 0 would be interpreted as
a & (b == 0), rather than what you almost certainly want, which is
(a & b) == 0.
This seems like an odd state of affairs. There is a good explanation, though. The bitwise operators were used in C’s precedessor, B, as logical operators. Therefore
(a == 0) & (b == 0), would be used to check both
b were 0. Having these bitwise operators have a lower precedence than comparison operators such as
==, meant you could just write
a == 0 & b == 0.
In order to make the transition from B to C, they decided to keep the precedence of these operators relative to
== the same, as Dennis Ritchie says:
In converting from B to C, one wants to replace & by && in such a statement; to make the conversion less painful, we decided to keep the precedence of the & operator the same relative to ==, and merely split the precedence of && slightly from &.
You probably also know that you can write hexadcimal literals, by prefixing it with
0x. There’s also a way of doing this for base 8, i.e. octal, literals. This is done by a prefix of
0o was provided. In C++14, Java and ES6, you can also use binary literals with the prefix
0b. This isn’t part of any C standard, although GCC implements it as an extension.
Pointers and Indices
Consider the following declaration:
To obtain the first element of the array you can do
a, but you can also do
0[a]. Why? Well, in C
a[b] is syntactic sugar for
*(a + b), so
a[b] is equivalent to
b[a] since addition is commutative.
Adding and Subtracting 1
If you want to get the value of an integer plus 1, you can write
~ being the bitwise NOT operator. Similarly, if you want to get the value of an integer minus 1, you can write
~-a. This is due to 2’s complement arithmetic.
This is technically platform-dependent, since the C specification doesn’t enforce that 2’s complement is used to represent signed integers, but in practice most computer systems will use 2’s complement. In 2’s complement, when negating a number, all bits are flipped and 1 is added. Since
~a only flips the bits, the value of
-a = ~a + 1, which means
~a = -a - 1. So
-(-a - 1) = a + 1. Similarly
-(-a) - 1 = a - 1.