警告 - 有符号和无符号整数表达式之间的比较

时间:2010-09-07 17:06:02

标签: c++ unsigned-integer

我目前正在使用 Accelerated C ++ ,并在练习2-3中遇到了一个问题。

程序的快速概述 - 程序基本上采用名称,然后在星号框架内显示问候语 - 即Hello!被*的框架包围着。

练习 - 在示例程序中,作者使用const int来确定问候语和星号之间的填充(空格)。然后,作为练习的一部分,他们要求读者询问用户输入他们想要填充的大小。

所有这一切似乎都很容易,我继续向用户询问两个整数(int)并存储它们并更改程序以使用这些整数,删除作者使用的整数,编译时虽然我得到了以下警告;

  

Exercise2-3.cpp:46:警告:有符号和无符号整数表达式之间的比较

经过一些研究后,似乎是因为代码试图将上述整数之一(int)与string::size_type进行比较,这很好。但我想知道 - 这是否意味着我应该将其中一个整数更改为unsigned int?明确说明我的整数是签名还是未签名是否很重要?

 cout << "Please enter the size of the frame between top and bottom you would like ";
 int padtopbottom;
 cin >> padtopbottom;

 cout << "Please enter size of the frame from each side you would like: ";
 unsigned int padsides; 
 cin >> padsides;

 string::size_type c = 0; // definition of c in the program
 if (r == padtopbottom + 1 && c == padsides + 1) { // where the error occurs

以上是代码的相关位,c属于string::size_type类型,因为我们不知道问候可能有多长时间 - 但是为什么我现在会在作者的代码中遇到这个问题使用const int时没有遇到问题?此外 - 对于可能已经完成 Accelerated C ++ 的任何人 - 这将在本书后面解释吗?

我在Linux Mint上使用g ++通过Geany,如果这有助于或有所作为(因为我读到它可以在确定string::size_type时)。

6 个答案:

答案 0 :(得分:81)

如果将变量与大小进行比较,通常最好将变量声明为unsignedsize_t,以避免此问题。尽可能使用您要比较的确切类型(例如,与std::string::size_type的长度进行比较时使用std::string

编译器会发出有关比较有符号和无符号类型的警告,因为有符号和无符号整数的范围不同,当它们相互比较时,结果可能会令人惊讶。如果必须进行这样的比较,则应该在检查之后将其中一个值显式转换为与另一个值兼容的类型,以确保转换有效。例如:

unsigned u = GetSomeUnsignedValue();
int i = GetSomeSignedValue();

if (i >= 0)
{
    // i is nonnegative, so it is safe to cast to unsigned value
    if ((unsigned)i >= u)
        iIsGreaterThanOrEqualToU();
    else
        iIsLessThanU();
}
else
{
    iIsNegative();
}

答案 1 :(得分:7)

我昨天在加速C ++中遇到问题2-3时遇到了完全相同的问题。关键是将要比较的所有变量(使用布尔运算符)更改为兼容类型。在这种情况下,这意味着string::size_type(或unsigned int,但由于此示例使用前者,我将坚持使用它,即使这两者在技术上是兼容的)。

请注意,正如您正确指出的那样,在原始代码中,他们为c计数器(本书第2.5节第30页)完成了这一操作。

使这个例子更复杂的原因是不同的填充变量(padsides和padtopbottom)以及所有计数器必须更改为string::size_type

以您的示例为例,您发布的代码最终会如下所示:

cout << "Please enter the size of the frame between top and bottom";
string::size_type padtopbottom;
cin >> padtopbottom;

cout << "Please enter size of the frame from each side you would like: ";
string::size_type padsides; 
cin >> padsides;

string::size_type c = 0; // definition of c in the program

if (r == padtopbottom + 1 && c == padsides + 1) { // where the error no longer occurs

请注意,在前一个条件中,如果未在string::size_type循环中将变量r初始化为for,则会收到错误。因此,您需要使用以下内容初始化for循环:

    for (string::size_type r=0; r!=rows; ++r)   //If r and rows are string::size_type, no error!

所以,基本上,一旦你在混合中引入string::size_type变量,任何时候你想对该项执行布尔操作,所有操作数必须具有兼容的类型才能在没有警告的情况下进行编译。

答案 2 :(得分:4)

在极端范围内,unsigned int可以变得大于int 因此,编译器会生成警告。如果您确定这不是问题,请随意将类型转换为相同的类型,以便警告消失(使用C ++强制转换,以便它们很容易被发现)。

或者,使变量的类型相同,以阻止编译器抱怨 我的意思是,是否可能有负填充?如果是,那么将其保存为int。否则你应该使用unsigned int并让流捕获用户键入负数的情况。

答案 3 :(得分:4)

有符号和无符号整数之间的重要区别 是最后一点的解释。最后一点 在签名类型中代表数字的符号,意思是: e.g:

0001是1签名和未签名 1001是-1签名和9无签名

(为了清楚解释,我避免了整个补充问题! 这并不完全是如何在内存中表示整数!)

你可以想象,如果你比较就会有所不同 用-1或+9。在许多情况下,程序员太懒了 将int计数为unsigned(膨胀为for循环头f.i.) 这通常不是问题,因为使用整数你必须计算到2 ^ 31 直到你的标志咬你。这就是为什么它只是一个警告。 因为我们懒得写'unsigned'而不是'int'。

答案 4 :(得分:0)

或使用this header library并写:

// |notEqaul|less|lessEqual|greater|greaterEqual
if(sweet::equal(valueA,valueB))

并且不关心签名/未签名或不同大小

答案 5 :(得分:0)

主要问题是底层硬件CPU仅具有比较两个有符号值或比较两个无符号值的指令。如果您向无符号比较指令传递一个带符号的负值,它将把它视为一个大的正数。因此,-1(所有位都打开(二进制补码))的位模式将变为相同位数的最大无符号值。

8位:-1有符号与255无符号相同 16位:-1有符号与65535无符号相同 等

因此,如果您具有以下代码:

int fd;
fd = open( .... );

int cnt;
SomeType buf;

cnt = read( fd, &buf, sizeof(buf) );

if( cnt < sizeof(buf) ) {
    perror("read error");
}

您会发现,如果由于文件描述符无效(或其他一些错误)而导致read(2)调用失败,则该cnt将被设置为-1。与无符号值sizeof(buf)进行比较时,if()语句将为false,因为0xffffffff不小于sizeof()某些(合理的,未被认为是最大大小)数据结构。

因此,如果要删除已签名/未签名的警告,则必须编写以上内容:

if( cnt < 0 || (size_t)cnt < sizeof(buf) ) {
    perror("read error");
}

这只是大声说出了问题。

1.  Introduction of size_t and other datatypes was crafted to mostly work, 
    not engineered, with language changes, to be explicitly robust and 
    fool proof.
2.  Overall, C/C++ data types should just be signed, as Java correctly
    implemented.

如果值太大,以至于找不到有效的带符号值类型,则说明您选择的语言使用的处理器太小或值的幅度太大。如果像金钱一样,每个数字都很重要,那么在大多数语言中都有可以使用的系统可以为您提供无限的精度。 C / C ++不能很好地做到这一点,并且您必须非常明确地了解类型中的所有内容,如此处许多其他答案所述。