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

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

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

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay