DEV Community

Pierre Gradot
Pierre Gradot

Posted on • Updated on

Let's try C++20 | std::cmp_* functions

Today, I have discovered a very simple (but yet very efficient and useful) feature from C++20: the std::cmp_* functions. They allow to compare 2 integers, which can have different signedness, without getting bitten by implicit conversions.

Let's have look at this piece of code:

#include <iostream>

int main()
{
    int a = -6;
    unsigned int b = 3;

    if (a < b) {
        std::cout << "OK: a is lower than b\n";
    } else {
        std::cout << "Oopsi!\n";
    }
}
Enter fullscreen mode Exit fullscreen mode

Yes, you've guessed right: it prints "Oopsi!".

Why?

Rule RSPEC-6214 from Sonar explains the issue very well:

Comparison between signed and unsigned integers is dangerous because it produces counterintuitive results outside of their common range of values.

When a signed integer is compared to an unsigned one, the former might be converted to unsigned. The conversion preserves the two’s-complement bit pattern of the signed value that often corresponds to a large unsigned result. For example, 2U < -1 is true.

C++20 introduced remedy to this common pitfall: a family of std::cmp_* functions defined in the header. These functions correctly handle negative numbers and lossy integer conversion. For example, std::cmp_less(2U, -1) is false.

This rule reports comparisons between signed and unsigned integers that involve negative numbers.

Let's try:

#include <iostream>
#include <utility>

int main()
{
    int a = -6;
    unsigned int b = 3;

    if (std::cmp_less(a, b)) {
        std::cout << "OK: a is lower than b\n";
    } else {
        std::cout << "Oopsi!\n";
    }
}
Enter fullscreen mode Exit fullscreen mode

And now the code prints "OK: a is lower than b" 😁

Note that your compiler can emits warnings about conversions like this. With GCC, the option -Wall is enough:

<source>: In function 'int main()':
<source>:10:11: warning: comparison of integer expressions of different signedness: 'int' and 'unsigned int' [-Wsign-compare]
   10 |     if (a == b) {
      |         ~~^~~~
Enter fullscreen mode Exit fullscreen mode

The problem is the same in C but -Wall doesn't add -Wsign-compare for C, only in C+.

PS: my first article on dev.to was about funny integers conversions (but you must speak French to read it 😅)

Discussion (1)

Collapse
ajinkyax profile image
Ajinkya Borade

the only thing I dont like about C++ is for every class you have to create its HEADER file. else everything is great