Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why does (type)-1 return the max value for a type in C++?

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?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

(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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading