Automatic conversion of int to unsigned int - c++

#include <iostream>
using namespace std;
int main() {
unsigned int u = 5;
int x = -1;
if(x>u) {
cout<<"Should not happen"<<endl;
} else {
cout<<"Ok"<<endl;
}
}
This code outputs Should not happen. I came across this when comparing the size of a string (size_t is an unsigned int or unsigned long long value) to an int.
It seems that C type casts int to unsigned int but in practice, it seems it would bring in bugs. Honestly, I would have preferred a compile-time error given how incompatible int is to unsigned int. I would like to know why the convention is like this?

You can enable -Wsign-compare -Werror in Clang: Try it online!
It'll produce a compile-time error (because of -Werror that treats warnings as errors):
.code.tio.cpp:7:9: error: comparison of integers of different signs: 'int' and 'unsigned int' [-Werror,-Wsign-compare]
if(x>u) {
~^~
1 error generated.
For some reason, -Wall -Werror in Clang (but not in GCC) doesn't produce any errors. But -Wall -Wextra -Werror does include -Wsign-compare, so you can use that.

Related

Signedness of int in while comparing with string.size() showing warning

So, i was writing down this code
void shortened(string s){
int cnt=0;
for(int i=0;i<s.size()-1;++i){
cnt++;
}
//some extra code
}
this for loop showed me a warning and i.e. of comparison of integer expressions of different signedness int and string::size_type. But as soon as I changed int i = 0 to unsigned int i=0 there was no warning. I know that the length of the string can never be zero and that's why the warning was shown because int i can hold negative numbers as well. But why the warning was being shown in the first place?
i-0;i<s.size()-1
in itself was very complete. I need to clear my doubt.
Assume you are using g++ as compiler. (gcc is the same while clang is unfamiliar to me)
This warning comes from the compilation option -Wall which asks the compiler to give you detailed warning for everything( Wall = Warning All). (For more information, you can visit https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options)
So g++ -o tmp tmp.cpp won't show such warning but g++ -o tmp -Wall tmp.cpp will.
Come back to the main topic: such a wired warning is shown due to the return type for string.size() is size_t and size_t is one of the unsigned types.
On my machine, I find size_t is defined in stddef.h as followed:
#define __SIZE_TYPE__ long unsigned int
typedef __SIZE_TYPE__ size_t;
You compare between an int and an unsigned int in for statement and this why here is such a warning.

Why doesn't C++ show a narrowing conversion error when casting a float to a char?

Compiling this code using g++ -std=c++17 -Wall -pedantic main.cpp doesn't produce any warnings:
#include <iostream>
#include <stdlib.h>
int main(int argc, char const *argv[]) {
for (int i = 0; i < 100; ++i) {
float x = 300.0 + rand();
char c = x;
std::cout << c << std::endl;
}
return 0;
}
Shouldn't it produce a narrowing error?
I did some research and I found that -Wall doesn't warn about type conversion issues.
Instead, use the flag -Wconversion in order to get a warning about potential type conversion issues.
Remarks:
For the users of VC++, /W4 will warn you about possible loss of data during type conversions

How to enable narrowing warnings in CodeBlocks?

I'm writing c++ program using codeblocks IDE
int main()
{
int i =0;
int f = 3.14;
i = f; //must give me a warning message, possible loss data.
}
Why the compilation not show a narrowing warning message?
How to enable that?
Note: I have fixed my compiler options as -std=c++11 -Wall
in the other compiler options put -Wconversion
( code::block 16 )
for:
int i =0;
int f = 3.14;
i = f;
warning: conversion to ‘int’ alters ‘double’ constant
value [-Wfloat-conversion]
Some useful warning that I use always:
-Wall -Weffc++ -Wextra -pedantic -Wfatal-errors -pedantic-errors

Why does g++ 4.8.1 issue a conversion warning

When I compile the code below with g++ 4.8.1 (64bit) in this way:
$ g++ -Wconversion -o main main.cpp
I get this result:
main.cpp: In function ‘int main()’:
main.cpp:12:20: warning: conversion to ‘int’ from ‘long unsigned int’ may alter its value [-Wconversion]
int i = sizeof(x)/sizeof(x[0]);
^
My expectation would be that the compiler should be able to evaluate the expression at compile time. If you make a similar program in plain c, gcc works like a charm.
Should this be considered a bug in g++ (e.g. clang++ does not have this problem)?
if you change the problematic line to something like:
char c = 0x10000000/0x1000000;
then the compiler does not complain. This suggest that some constant evaluation is done before warning generation.
main.cpp:
#include <iostream>
struct foo {
int a;
int b;
};
foo x[50];
int main()
{
int i = sizeof(x)/sizeof(x[0]);
std::cout << i << std::endl;
return 0;
}
int i = sizeof(x)/sizeof(x[0]);
//int <-- std::size_t <-- std::size_t / std::size_t
The type of the expression sizeof(x)/sizeof(x[0]) is std::size_t which on your machine is unsigned long int. So conversion from this type to int is data-loss, if the source is bigger in size than the target.
Though, I agree that in your case, there would not be actual data-loss if the compiler actually computes the value, but I guess it applies -Wconversion before the actual computation.
sizeof() returns you std::size_t not int! So cast it or declare i as std::size_t.
std::size_t i = sizeof(x)/sizeof(x[0]);

Why does not g++ or clang elicit a warning when truncating a non-const variable by assigning it to a variable of smaller type?

Both clang 2.9 and g++ 4.1.2 will generate a warning when the variable x is declared constant in the code snippet below. However when const is removed, as it has been in the snippet, neither of the compilers generates a warning even when executed with the following parameters which are the strictest I know: "-Wall -Wextra -pedantic -ansi"
Why won't the compilers deduce and report the same warning since x isn't volatile and cannot possibly be modified before the type conversion?
#include <iostream>
int main(int argc, char **argv)
{
unsigned int x = 1000;
const unsigned char c = x;
const unsigned int x_ = c;
std::cout << "x=" << x << " x_=" << x_ << std::endl;
return 0;
}
With const unsigned int x = 1000; g++ provides the message "warning: large integer implicitly truncated to unsigned type" and clang "warning: implicit conversion from 'const unsigned int' to 'const unsigned char' changes value from 1000 to 232 [-Wconstant-conversion]".
Is there any way to automatically detect this case without manually inspecting the code or relying on correctly designed unit tests?
For GCC, add the flag -Wconversion and you will get the desired warning. It's not a part of -Wall since so much code just ignores these types of things. I always have it turned on since it finds otherwise hard to debug defects.
If it is a const the compiler can see its value and warn about the truncation. If it is not a const, it cannot, despite the initialisation. This:
const unsigned int x = 1000;
const unsigned char c = x;
is equivalent to:
const unsigned char c = 1000;
I've run gcc with -O3 -fdump-tree-vrp, and what I see in the dump is:
std::__ostream_insert<char, std::char_traits<char> > (&cout, &"x="[0], 2);
D.20752_20 = std::basic_ostream<char>::_M_insert<long unsigned int> (&cout, 1000);
std::__ostream_insert<char, std::char_traits<char> > (D.20752_20, &" x_="[0], 4);
D.20715_22 = std::basic_ostream<char>::_M_insert<long unsigned int> (D.20752_20, 232);
i.e. it just inlines the constants 1000 and 232 in the cout statement!
If I run it with -O0, it doesn't dump anything, despite -ftree-vrp and -ftree-ccp switches.
Seems like gcc inlines the constants before it can emit the warnings...