While reading the source code for RakNet on GitHub, I came across the following in RakNetDefines.h
.
typedef unsigned char RPCIndex;
const int MAX_RPC_MAP_SIZE=((RPCIndex)-1)-1;
const int UNDEFINED_RPC_INDEX=((RPCIndex)-1);
When running the following code via an online C++ compiler:
#include <iostream>
typedef unsigned char RPCIndex;
const int MAX_RPC_MAP_SIZE=((RPCIndex)-1)-1;
const int UNDEFINED_RPC_INDEX=((RPCIndex)-1);
int main() {
std::cout << MAX_RPC_MAP_SIZE << " ";
std::cout << UNDEFINED_RPC_INDEX;
return 0;
}
I get 254 255
as the output. While I know that 255
is (typically) the maximum value for an unsigned char
in C++, I was shocked to see that simply putting the name of a type and subtracting one from it resulted in it's maximum value. Furthermore, writing (RPCIndex)-0
evaluates to 0
. Why is this the case in C++? Is there a historical reason for it, is it just convenient, or am I missing something?
(RPCIndex)-1
is parsed as a C-style cast expression of the form (T)E
where T
is a type and E
an unary expression.
In this case T
is the type RPCIndex
and E
is the expression -1
which is a unary minus operator applied to the 1
integer literal.
The result is the value -1
converted to RPCIndex
. Because RPCIndex
is an unsigned integral type, the result is the representable value of RPCIndex
congruent to -1
modulo 2**w
where w
is the width of the RPCIndex
integer type. In other words, it produces 2**w-1
, the largest representable value of the unsigned integer type.
I guess you can see how (RPCIndex)-0
works...
This -1
cast trick originates from C where there is no other way to name the maximum value of some aliased unsigned integer type without knowing what it aliases or what its maximum value is apriori.
In C++ it can be expressed much more clearly what the intent is with std::numeric_limits
from <limits>
. The -1
trick is not necessary anymore:
const int UNDEFINED_RPC_INDEX = std::numeric_limits<RPCIndex>::max();
In general the code looks more like C than (modern) C++ code, although it behaves as expected in C++ as well.