87

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

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

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

这一切似乎很容易,我继续向用户询问两个整数(int)并存储它们并更改程序以使用这些整数,删除作者使用的整数,尽管我收到以下警告;

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

经过一些研究,这似乎是因为代码尝试将上述整数之一 ( 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

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

我在通过 Geany 使用 g++ 的 Linux Mint 上,如果这有帮助或有所作为(正如我读到的那样,在确定什么string::size_type是它时它可以)。

4

6 回答 6

115

通常最好将变量声明为unsignedsize_t它们与大小进行比较,以避免此问题。只要有可能,请使用您将与之比较的确切类型(例如,std::string::size_type与 astd::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();
}
于 2010-09-07T17:09:54.043 回答
9

我昨天在加速 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_typefor循环中将变量 r 初始化为 a,则会收到错误消息。因此,您需要使用以下方法初始化 for 循环:

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

因此,基本上,一旦您将string::size_type变量引入混合中,任何时候您想要对该项目执行布尔运算,所有操作数都必须具有兼容的类型才能编译而不会出现警告。

于 2014-01-07T16:25:51.550 回答
6

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

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

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

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

于 2010-09-07T17:32:32.910 回答
4

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

或者,使变量具有相同的类型以阻止编译器抱怨。
我的意思是,是否有可能有一个负填充?如果是这样,请将其保留为 int。否则,您可能应该使用 unsigned int 并让流捕获用户输入负数的情况。

于 2010-09-07T17:13:33.190 回答
1

主要问题是底层硬件 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() 语句将是错误的,因为 0xffffffff 不小于 sizeof() 一些(合理的,不是炮制为最大大小的)数据结构。

因此,您必须编写上述 if,以将已签名/未签名警告删除为:

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++ 只是不能很好地做到这一点,并且您必须非常明确地了解与此处许多其他答案中提到的类型有关的所有内容。

于 2019-07-15T16:07:01.883 回答
0

或使用此头库并编写:

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

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

于 2015-04-09T11:23:47.267 回答