[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