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

发布于 2024-09-18 14:23:27 字数 1310 浏览 2 评论 0原文

我目前正在学习加速 C++,并在练习 2-3 中遇到了问题。

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

练习 - 在示例程序中,作者使用 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 上通过 Geany 使用 g++,如果这有帮助或有影响的话(正如我读到的,在确定 string::size_type 是什么时它可以)。

I am currently working through Accelerated C++ and have come across an issue in exercise 2-3.

A quick overview of the program - the program basically takes a name, then displays a greeting within a frame of asterisks - i.e. Hello ! surrounded framed by *'s.

The exercise - In the example program, the authors use const int to determine the padding (blank spaces) between the greeting and the asterisks. They then ask the reader, as part of the exercise, to ask the user for input as to how big they want the padding to be.

All this seems easy enough, I go ahead ask the user for two integers (int) and store them and change the program to use these integers, removing the ones used by the author, when compiling though I get the following warning;

Exercise2-3.cpp:46: warning: comparison between signed and unsigned integer expressions

After some research it appears to be because the code attempts to compare one of the above integers (int) to a string::size_type, which is fine. But I was wondering - does this mean I should change one of the integers to unsigned int? Is it important to explicitly state whether my integers are signed or unsigned?

 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

Above are the relevant bits of code, the c is of type string::size_type because we do not know how long the greeting might be - but why do I get this problem now, when the author's code didn't get the problem when using const int? In addition - to anyone who may have completed Accelerated C++ - will this be explained later in the book?

I am on Linux Mint using g++ via Geany, if that helps or makes a difference (as I read that it could when determining what string::size_type is).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

客…行舟 2024-09-25 14:23:27

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

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

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();
}

It is usually a good idea to declare variables as unsigned or size_t if they will be compared to sizes, to avoid this issue. Whenever possible, use the exact type you will be comparing against (for example, use std::string::size_type when comparing with a std::string's length).

Compilers give warnings about comparing signed and unsigned types because the ranges of signed and unsigned ints are different, and when they are compared to one another, the results can be surprising. If you have to make such a comparison, you should explicitly convert one of the values to a type compatible with the other, perhaps after checking to ensure that the conversion is valid. For example:

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();
}
独﹏钓一江月 2024-09-25 14:23:27

昨天我在解决 Accelerated 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

请注意,在前面的条件中,如果您没有将变量 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 变量引入混合中,任何时候您想要对该项目执行布尔操作时,所有操作数必须具有兼容的类型才能编译而不会出现警告。

I had the exact same problem yesterday working through problem 2-3 in Accelerated C++. The key is to change all variables you will be comparing (using Boolean operators) to compatible types. In this case, that means string::size_type (or unsigned int, but since this example is using the former, I will just stick with that even though the two are technically compatible).

Notice that in their original code they did exactly this for the c counter (page 30 in Section 2.5 of the book), as you rightly pointed out.

What makes this example more complicated is that the different padding variables (padsides and padtopbottom), as well as all counters, must also be changed to string::size_type.

Getting to your example, the code that you posted would end up looking like this:

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

Notice that in the previous conditional, you would get the error if you didn't initialize variable r as a string::size_type in the for loop. So you need to initialize the for loop using something like:

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

So, basically, once you introduce a string::size_type variable into the mix, any time you want to perform a boolean operation on that item, all operands must have a compatible type for it to compile without warnings.

箜明 2024-09-25 14:23:27

有符号整数和无符号整数之间的重要区别
是最后一位的解释。最后一点
有符号类型中表示数字的符号,含义:
例如:

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

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

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

The important difference between signed and unsigned ints
is the interpretation of the last bit. The last bit
in signed types represent the sign of the number, meaning:
e.g:

0001 is 1 signed and unsigned
1001 is -1 signed and 9 unsigned

(I avoided the whole complement issue for clarity of explanation!
This is not exactly how ints are represented in memory!)

You can imagine that it makes a difference to know if you compare
with -1 or with +9. In many cases, programmers are just too lazy
to declare counting ints as unsigned (bloating the for loop head f.i.)
It is usually not an issue because with ints you have to count to 2^31
until your sign bit bites you. That's why it is only a warning.
Because we are too lazy to write 'unsigned' instead of 'int'.

猫卆 2024-09-25 14:23:27

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

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

At the extreme ranges, an unsigned int can become larger than an int.
Therefore, the compiler generates a warning. If you are sure that this is not a problem, feel free to cast the types to the same type so the warning disappears (use C++ cast so that they are easy to spot).

Alternatively, make the variables the same type to stop the compiler from complaining.
I mean, is it possible to have a negative padding? If so then keep it as an int. Otherwise you should probably use unsigned int and let the stream catch the situations where the user types in a negative number.

指尖上得阳光 2024-09-25 14:23:27

主要问题是底层硬件 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 编写为删除签名/未签名警告:

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++ 在这方面做得不好,您必须非常明确地了解类型的所有内容,正如这里的许多其他答案中提到的那样。

The primary issue is that underlying hardware, the CPU, only has instructions to compare two signed values or compare two unsigned values. If you pass the unsigned comparison instruction a signed, negative value, it will treat it as a large positive number. So, -1, the bit pattern with all bits on (twos complement), becomes the maximum unsigned value for the same number of bits.

8-bits: -1 signed is the same bits as 255 unsigned
16-bits: -1 signed is the same bits as 65535 unsigned
etc.

So, if you have the following code:

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

int cnt;
SomeType buf;

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

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

you will find that if the read(2) call fails due to the file descriptor becoming invalid (or some other error), that cnt will be set to -1. When comparing to sizeof(buf), an unsigned value, the if() statement will be false because 0xffffffff is not less than sizeof() some (reasonable, not concocted to be max size) data structure.

Thus, you have to write the above if, to remove the signed/unsigned warning as:

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

This just speaks loudly to the problems.

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.

If you have values so large that you can't find a signed value type that works, you are using too small of a processor or too large of a magnitude of values in your language of choice. If, like with money, every digit counts, there are systems to use in most languages which provide you infinite digits of precision. C/C++ just doesn't do this well, and you have to be very explicit about everything around types as mentioned in many of the other answers here.

浅沫记忆 2024-09-25 14:23:27

或使用 这个头库 并写入:

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

并且不关心关于有符号/无符号或不同大小

or use this header library and write:

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

and don't care about signed/unsigned or different sizes

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文