我目前正在努力 加速C ++ 并在练习2-3中遇到了一个问题。

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

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

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

练习2-3.CPP:46:警告:签名和未签名整数表达式之间的比较

经过一项研究,似乎是因为代码试图比较上述整数之一(intstring::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_typestd::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 ++只是做得不好,您必须在此处许多其他答案中提到的所有类型上都非常明确。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top