C++ Basics: Compare Signed and Unsigned Integers Safely
Use std::cmp_less to compare integer values without converting a negative number to unsigned.
Prepare a scratch directory
Tested on Linux x86_64 with GCC 14.2.0. Install a C++20-capable compiler and standard-library development headers, with g++ on PATH. You also need Bash, a text editor, and the mktemp, rm, and rmdir utilities. No third-party library is required.
Keep the same terminal open. Stop if setup fails, before saving the source:
start_directory="$PWD"
work_directory="$(mktemp -d)" || exit 1
cd -- "$work_directory" || exit 1Run the example
Save this as cmp-less-signed-unsigned-demo.cpp:
#include <cstddef>
#include <iostream>
#include <utility>
int main()
{
const std::size_t count = 3;
std::cout << std::boolalpha;
for (int index : {-1, 0, 2, 3}) {
const bool below = std::cmp_less(index, count);
const bool valid = std::cmp_greater_equal(index, 0) && below;
std::cout << index << ": below=" << below
<< ", valid=" << valid << '\n';
}
}Compile and run it. The program runs only after compilation succeeds:
g++ -std=c++20 -Wall -Wextra -Werror -pedantic cmp-less-signed-unsigned-demo.cpp -o cmp-less-signed-unsigned-demo &&
./cmp-less-signed-unsigned-demoObserved output:
-1: below=true, valid=false
0: below=true, valid=true
2: below=true, valid=true
3: below=false, valid=falseRead the result
Minus one is mathematically less than three, but it is not a valid index. Checking both bounds distinguishes comparison from index validation. Three is excluded because the upper bound is exclusive.
Apply it carefully
These C++20 helpers support signed and unsigned integer types, but not bool, plain char, character types such as wchar_t, or enums. Check the lower bound as well when a negative value is invalid; a safe comparison alone does not make indexing safe.
The C++ working draft describes the relevant rules. This example builds in C++20 mode; the current working draft also documents later additions.
Clean up
Remove only the source and executable created here, then return to the starting directory:
rm -- cmp-less-signed-unsigned-demo.cpp cmp-less-signed-unsigned-demo
cd -- "$start_directory" || exit 1
rmdir -- "$work_directory"
unset start_directory work_directoryIf the directory is not empty, inspect its remaining contents before removing anything else.
Acknowledgements
This post was created with assistance from AI.