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

Tim*_*ton 66 c++ unsigned-integer

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

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

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

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

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

经过一些研究后,似乎是因为代码试图将上述整数(int)之一与a进行比较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
Run Code Online (Sandbox Code Playgroud)

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

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

Kri*_*son 90

将变量声明为unsignedsize_t将它们与大小进行比较通常是个好主意,以避免此问题.尽可能使用您要比较的确切类型(例如,std::string::size_typestd::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();
}
Run Code Online (Sandbox Code Playgroud)

  • 我知道当前的C标准有时要求负的有符号值比无符号值大,但是在任何情况下都不应该被认为是弃用的吗?我希望看到标准演变为至少*允许*编译器产生算术正确的行为(意味着如果有符号值为负,则它比较小,如果无符号值超过有符号类型的最大值,则比较大).在没有明确的类型转换的情况下,编译器需要产生愚蠢的行为似乎很奇怪. (10认同)
  • 为了证明"结果可能令人惊讶",下面的程序(在顶部插入`#include <cstdio>`之后......我使用g ++ 4.4.7)将打印"true",说明确实,(signed)-1大于(unsigned)12:`int main(int,char**){int x = -1; unsigned int y = 12; printf("x> y:%s \n",x> y?"true":"false"); 返回0; }` (5认同)
  • @supercat:由于整数比较编译为单个机器指令,并且任何测试或边缘情况处理都需要多个机器指令,你建议的不太可能被添加为C特征......它肯定不是默认行为,因为即使程序员知道没有必要,也会不必要地杀死性能. (3认同)

eri*_*ric 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
Run Code Online (Sandbox Code Playgroud)

请注意,在之前的条件,你会如果你没有初始化变量r为得到错误string::size_typefor循环.因此,您需要使用以下内容初始化for循环:

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

所以,基本上,一旦你将一个string::size_type变量引入混合中,只要你想对该项执行布尔运算,所有操作数必须具有兼容的类型,以便在没有警告的情况下进行编译.


And*_*asT 6

有符号整数和无符号整数之间的重要区别在于最后一位的解释。有符号类型的最后一位代表数字的符号,意思是:例如:

0001 是 1 有符号和无符号 1001 是 -1 有符号和 9 无符号

(为清楚起见,我避免了整个补码问题!这并不是整数在内存中的表示方式!)

您可以想象,知道与 -1 还是 +9 进行比较会有所不同。在许多情况下,程序员只是懒得将计数 int 声明为无符号(使 for 循环头 fi 膨胀)这通常不是问题,因为对于 int,您必须计数到 2^31,直到您的符号位咬住您为止。这就是为什么它只是一个警告。因为我们懒得写 'unsigned' 而不是 'int'。

  • 有符号整数的内部表示依赖于编译器(即机器)。由于某些问题(+/- 零就是其中之一),您的符号位符号并未被广泛使用。大多数机器使用二进制补码概念来表示负数。优点是也可以使用普通(无符号)算术而无需任何更改。-1 在 2 的补码概念中是 1111 btw。 (9认同)