Modern C++ continuous integration build pipelines might produce huge logs which may be easily overlooked. Among other errors/warnings, a potential risk caused by invalid narrowing assignments might be lurking in those dark corners... This write up is a little reminder about an essential feature in modern C++ compilers and can help defend against that specific problem.
Prior to C++11, the following was a valid assignment and still is even in C++20 or higher ...
unsigned int unsignedSinceBirth = 10;unsignedSinceBirth = -10; // assigning a negative value to an unsigned container
printUnsignedVal(unsignedSinceBirth);
which when compiled using these options "g++ -std=c++20 <cpp files> -o <executable-name>" does not even emit a warning. And an executable is generated successfully.
The output of running that code is an arbitrary unexpected value.error: narrowing conversion of ‘-10’ from ‘int’ to ‘unsigned int’ [-Wnarrowing]
But when the assignment happens in the following manner, compiler only emits a warning and the compilation still succeeds:
// .. somewhere else in the code
int rougeInteger = -10;
unsignedSinceBirth = {rougeInteger};
Compiling the revised code does not fail and that's a bad thing. G++ only emits a warning:
warning: narrowing conversion of ‘rougeUnsignedNum’ from ‘int’ to ‘unsigned int’ [-Wnarrowing]
In absence of eagle eyes, that warning will most likely go unnoticed in large build logs and the compilation will succeed. It turns out there is a way to enforce the compiler detect such assignments.
If we include "-Werror" option in the G++ command line as follows:
"g++ -std=c++20 -Werror <cpp files> -o <executable-name>"
The complier will emit an error and compilation will not be successful and that's the effect we were looking for.
Crux: Always pay attention to what compiler is trying to tell us. If it's not telling, force it to say something :)
Note: Compilation using LLVM clang as follows complains with an error without needing an explicit option:
"clang -std=c++20 <cpp files> -o <executable-name>"
with the following error:
error: non-constant-expression cannot be narrowed from type 'int' to 'unsigned int' in initializer list [-Wc++11-narrowing]
Comments
Post a Comment