警告 - 签名和未签名的整数表达式之间的比较
-
01-10-2019 - |
题
我目前正在努力 加速C ++ 并在练习2-3中遇到了一个问题。
该程序的快速概述 - 该程序基本上取名,然后在星号框架内显示一个问候 - 即您好!被 *的包围。
练习 - 在示例程序中,作者使用 const int
确定问候和星号之间的填充(空白空间)。然后,他们要求读者作为练习的一部分,要求用户输入有关他们希望填充有多大的输入。
所有这些似乎都很容易,我继续向用户询问两个整数(int
)并将其存储并更改程序以使用这些整数,并在编译以下警告时删除作者使用的整数;
练习2-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
?此外 - 对于可能已经完成的任何人 加速C ++ - 这将在书中稍后解释吗?
我正在使用Geany使用G ++的Linux Mint上,如果有帮助或有所作为(正如我所读到的那样,可以在确定什么时可以 string::size_type
是)。
解决方案
通常是一个好主意 unsigned
或者 size_t
如果将它们与尺寸进行比较,以避免此问题。只要有可能,请使用确切的类型,您将与(例如,使用) std::string::size_type
与 std::string
长度)。
编译器警告说要比较签名和未签名类型,因为签名和未签名的INT的范围是不同的,并且当它们相互比较时,结果可能令人惊讶。如果您必须进行这样的比较,则应该明确将其中一个值转换为与另一种类型的类型,也许是在检查后确保转换有效的。例如:
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();
}
其他提示
昨天我遇到了同样的问题,方法是通过问题2-3加速的C ++。关键是要将您将要比较(使用布尔运算符)的所有变量更改为兼容类型。在这种情况下,这意味着 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
请注意,在上一个条件下,如果您不初始化变量r为一个 string::size_type
在里面 for
环形。因此,您需要使用类似的内容来初始化for循环。
for (string::size_type r=0; r!=rows; ++r) //If r and rows are string::size_type, no error!
因此,基本上,一旦您引入了 string::size_type
混音中的变量,每当您想在该项目上执行布尔操作时,所有操作数都必须具有兼容类型,以便在不警告的情况下进行编译。
签名和未签名的INT之间的重要区别是对最后一位的解释。签名类型中的最后位表示数字的符号,含义:例如:
0001是1个签名,未签名的1001为-1签名和9个未签名
(我避免了整个补充问题以清楚说明!这并不是记忆中INT的代表!)
您可以想象,知道您是否与-1或+9进行比较会有所作为。在许多情况下,程序员太懒了,无法将INT计数为未签名(blo blo for for loop head fi),这通常不是问题,因为在ints上,您必须计算到2^31,直到您的符号咬住您。这就是为什么这只是警告。因为我们懒得写“未签名”而不是“ int”。
在极端范围内,未签名的int可能比int更大。
因此,编译器会发出警告。如果您确定这不是问题,请随时将类型施放到同一类型中,以便警告消失(使用C ++铸件,以便易于发现)。
或者,使变量具有相同的类型,以阻止编译器投诉。
我的意思是,有可能有负填充吗?如果是这样,请将其保留为INT。否则,您可能应该使用未签名的int,并让流捕获用户在负数中键入的情况。
或使用 这个标题库 和写:
// |notEqaul|less|lessEqual|greater|greaterEqual
if(sweet::equal(valueA,valueB))
并且不在乎签名/未签名或不同的大小
主要问题是,基本硬件CPU仅具有比较两个签名值或比较两个无符号值的指令。如果您通过未签名的比较指令签名的负值,它将将其视为一个较大的正数。因此,-1,所有位上的位模式(两次补充)成为相同数量位的最大无符号值。
8位:-1签名与255个未签名的16位相同的位:-1签名与65535 Unsigned等相同的位相同。
因此,如果您有以下代码:
int fd;
fd = open( .... );
int cnt;
SomeType buf;
cnt = read( fd, &buf, sizeof(buf) );
if( cnt < sizeof(buf) ) {
perror("read error");
}
您会发现,如果读取(2)由于文件描述符变得无效(或其他错误)而失败,则CNT将设置为-1。与sizeof(buf)相比,一个无符号值时,if()语句将是错误的,因为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 ++只是做得不好,您必须在此处许多其他答案中提到的所有类型上都非常明确。