DEV Community

Pierre Gradot
Pierre Gradot

Posted on • Edited on

3

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 😅)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

Top comments (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

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more