Comparison between unsigned integer expressions and 0x80000000

I have the following code:

#include <iostream> using namespace std; int main() { int a = 0x80000000; if(a == 0x80000000) a = 42; cout << "Hello World! :: " << a << endl; return 0; } 

Output signal

 Hello World! :: 42 

so the comparison works. But the compiler tells me

 g++ -c -pipe -g -Wall -W -fPIE -I../untitled -I. -I../bin/Qt/5.4/gcc_64/mkspecs/linux-g++ -o main.o ../untitled/main.cpp ../untitled/main.cpp: In function 'int main()': ../untitled/main.cpp:8:13: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] if(a == 0x80000000) ^ 

So the question is: why is 0x80000000 an unsigned int? Can I somehow sign it to get rid of the warning?

As far as I understand, 0x80000000 would be INT_MIN as out of range for a positive integer. but why does the compiler assume that I want a positive number?

I am compiling with gcc version 4.8.1 20130909 on linux.

+4
source share
3 answers

0x80000000 is an unsigned int, because the value is too large to match the int , and you did not add L to indicate that it is long.

A warning is issued because unsigned in C / C ++ has rather strange semantics, and therefore it is very easy to make mistakes in code by mixing unsigned and unsigned integers. This confusion is often a source of errors, especially because the standard historical accident library chose unsigned for the size of the containers ( size_t ).

An example that I often use to show how subtle the problem is, consider

 // Draw connecting lines between the dots for (int i=0; i<pts.size()-1; i++) { draw_line(pts[i], pts[i+1]); } 

This code seems fine, but has an error. In case the vector pts empty pts.size() is 0 , but the surprising part comes here too, pts.size()-1 is a huge pointless number (today it is often 4294967295, but it depends on the platform), and the cycle will use an invalid indexes (with undefined behavior).

Here changing the variable to size_t i will remove the warning, but will not help, since the same error remains ...

The core of the problem is that with unsigned values, a < b-1 and a+1 < b not the same even for very commonly used values, such as zero; therefore, using unsigned types for non-negative values ​​such as container size is a bad idea and a source of errors.

Also note that your code is not correctly portable C ++ on platforms where this value does not fit into an integer, as the behavior for overflow is defined for unsigned types, but not for ordinary integers. C ++, which relies on what happens when an integer goes out of bounds, has undefined behavior.

Even if you know what is happening on a particular hardware platform, note that the compiler / optimizer assumes that an invalid integer overflow of the chain never occurs: for example, a test like a < a+1 , where a is a regular int can always be considered true c ++ compiler.

+5
source

You seem to be confusing 2 different questions: coding for something and the meaning of something . Here is an example: you see the number 97. This is a decimal encoding. But the meaning of this number is something completely different. It can denote the ASCII 'a' symbol, very hot temperature, geometric angle in a triangle, etc. You cannot deduce the value from the encoding. Someone should provide you with a context (e.g. ASCII map, temperature, etc.).

Back to your question: 0x80000000 is encoding. While INT_MIN matters. They are not interchangeable and not comparable. On certain equipment, in some contexts, they can be equal, like 97, and "a" are equal in the ASCII context.

The compiler warns you of ambiguity in value, not in encoding. One way to give meaning to a particular encoding is to cast a statement. Like (unsigned short)-17 or (student*)ptr;

In a 32-bit system or 64 bits with backward compatibility of int and unsigned int there is a 32-bit encoding, as in 0x80000000 , but for 64 bits MIN_INT will not be equal to this number.

In any case, the answer to your question is: to remove the warning, you must give an identical context to both the left and right comparison expressions. You can do this in many ways. For instance:

(unsigned int)a == (unsigned int)0x80000000 or (__int64)a == (__int64)0x80000000 or even crazy (char *)a == (char *)0x80000000 or in any other way if you observe the following rules:

  • You do not lower the encoding level (do not reduce the number of bits that are required). Like (char)a == (char)0x80000000 is incorrect, because you reduce 32 bits by 8 bits
  • You must specify both the left and right sides of the == operator in the same context. For example, as (char *)a == (unsigned short)0x80000000 is incorrect, an error / warning message is issued.

I want to give you another example of how important the difference between coding and value is. Look at the code

 char a = -7; bool b = (a==-7) ? true : false; 

What is the result of 'b' ? The answer is shocking: it is undefined. Some compilers (usually Microsoft visual studio) will compile a program in which b will get true , while on Android compilers NDK b will get false . The reason is that the Android NDK treats the type char as an unsigned char , and Visual Studio treats the char as a signed char . So, on Android phones, the encoding -7 actually has a value of 249 and is not equal to the value (int) -7. The correct way to fix this problem is to define "a" as a signed char:

  signed char a = -7; bool b = (a==-7) ? true : false; 
+2
source

0x80000000 is considered unsigned by default. You can avoid the warning as follows:

  if (a == (int)0x80000000) a=42; 

Edit after comment:

Another (maybe better) way would be

  if ((unsigned)a == 0x80000000) a=42; 
+1
source

All Articles