[Development] Compare signed and unsigned integers in Qt

Tatiana Borisova tatiana.borisova at qt.io
Mon Aug 12 13:57:56 CEST 2024


Comparison between signed and unsigned integer types seems to be a simple case, but sometimes it leads to nasty bugs in the code.

Briefly recall the problem:
Each integer type with opposite signed and unsigned identificators occupies the same size in the memory.
But being unsigned, it can only carry non-negative numbers. On the other hand, being signed the integer type represents both signed and unsigned numbers.

The signed integer type uses 1 bit from number representation as the sign detector (0 - positive, 1 - negative).
It means that, given the fact that the signed and unsigned occupy the same amount of memory, the range of values ​​will be different.

For example, if the integer has 32 bits size in the system:
- signed int value range is (+-)2^31 (from -2,147,483,648 to 2,147,483,647)
- unsigned int value range is 2^32 (from 0 to 4,294,967,295)

Another important thing is the signed type uses the Two's complement method for numbers representation.
The method does following steps:
- It reserves the first bit for distinguishing negative and positive numbers
- It inverts the rest of bits and add 1.

For example, after applying the Two's complement method, 'signed int a = -1' is represented as '111111111’111111111’111111111’111111111' (32 bit integer) .
But the unsigned type doesn't use such a method. In case of unsigned int, the '111111111’111111111’111111111’111111111' is just the biggest possible value for 32-bit integer (4,294,967,295).

As a result, the same number representation ​​may be interpreted differently.

There is a way to detect such problem by using "-werror/-wsign-compare" compiler options.
Options find all places that execute such comparisons and interpret them like errors.
But fixing comparison errors always was on a developer.

Nowadays C++20 introduces a safe way to compare signed and unsigned integer types.
A new API description can be found here: https://en.cppreference.com/w/cpp/utility/intcmp <https://en.cppreference.com/w/cpp/utility/intcmp>
The solution treats all negative numbers as smaller then any non-negative.
The nice thing about the new API it is simple and can be easily ported to the older C++ versions.
So we introduced the backport as a part of a Qt 'q20' namespace.
The implementation can be found here: https://codereview.qt-project.org/c/qt/qtbase/+/570370/29/src/corelib/global/q20utility.h

The backport gives to Qt users a possibility to start using the safe comparison with C++17 and since Qt 6.9.
The 'q20' namespace checks if std implementation is available and takes it, otherwise it takes our implementation.

How to use it: https://codereview.qt-project.org/c/qt/qtbase/+/578720
In short, I hope it can be useful for development. And let's use the API (when it's suitable).

Also, I am thinking about better detection methods. A clang-tidy tool is a potential candidate.

Best regards,
Tatiana
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.qt-project.org/pipermail/development/attachments/20240812/ec9554f9/attachment-0001.htm>


More information about the Development mailing list