在处理vector.size()aka size_type
vector<cv::Mat> rebuiltFaces;
int rebuildIndex = 1;
cout << "rebuiltFaces size is " << rebuiltFaces.size() << endl;
while( rebuildIndex >= rebuiltFaces.size() ) {
cout << (rebuildIndex >= rebuiltFaces.size()) << " , " << rebuildIndex << " >= " << rebuiltFaces.size() << endl;
--rebuildIndex;
}
我从控制台出来的是
rebuiltFaces size is 0
1 , 1 >= 0
1 , 0 >= 0
1 , -1 >= 0
1 , -2 >= 0
1 , -3 >= 0
如果我不得不猜测我会说编译器盲目地将rebuildIndex转换为unsigned和+ - 但是导致事情表现得很奇怪,但我真的不确定。有谁知道吗?
答案 0 :(得分:3)
正如其他人所指出的,这是由于某种原因
反直觉规则C ++在比较不同的值时适用
符号类型;该标准要求编译器将两个值都转换为
unsigned
。出于这个原因,它通常被认为是最佳实践
避免unsigned
,除非你正在做一些操作(实际的
数值是无关紧要的)。遗憾的是,标准容器
不要遵循这个最佳实践。
如果你知道矢量的大小永远不会溢出
int
,然后您可以将std::vector<>::size()
的结果转换为
int
并完成它。然而,这并非没有危险;作为马克
吐温说:“这不是你不知道杀死你的东西,而是你
我知道这不是真的。“如果没有验证的话
插入向量,然后更安全的测试将是:
while ( rebuildFaces.size() <= INT_MAX
&& rebuildIndex >= (int)rebuildFaces.size() )
或者,如果你真的不指望这种情况,并准备中止,如果它
发生,设计(或找到)checked_cast
函数,然后使用它。
答案 1 :(得分:1)
在我能想到的任何现代计算机上,有符号整数表示为两个补码。 32位int max是0x7fffffff,int min是0x80000000,这使得当值为负时添加很容易。系统工作使得0xffffffff为-1,并且向其中加1会导致所有位翻转并且等于零。在硬件中实现它是非常有效的。
当数字从有符号值转换为无符号值时,存储在寄存器中的位不会改变。这使得一个几乎为-1的负值成为一个巨大的无符号数(unsigned max),如果内部的代码没有做一些会因为访问内存而导致程序崩溃的事情,这会使该循环运行很长时间。吨。
它完全合乎逻辑,不一定是你期望的逻辑。
示例...
$ cat foo.c
#include <stdio.h>
int main (int a, char** v) {
unsigned int foo = 1;
int bar = -1;
if(foo < bar) printf("wat\n");
return 0;
}
$ gcc -o foo foo.c
$ ./foo
wat
$
答案 2 :(得分:1)
在C和C ++语言中,当无符号类型具有与有符号类型相同或更大的宽度时,在无符号类型的域中执行混合有符号/无符号比较。被烧录的值被隐式转换为无符号类型。 “编译器”在这里“盲目地”做任何事都没什么。从一开始就像在C和C ++中那样。
这是你的例子中发生的事情。您的rebuildIndex
已隐式转换为vector<cv::Mat>::size_type
。即此
rebuildIndex >= rebuiltFaces.size()
实际上被解释为
(vector<cv::Mat>::size_type) rebuildIndex >= rebuiltFaces.size()
当有符号值转换为无符号类型时,转换是按照模运算的规则执行的,这是C和C ++中无符号算术背后的一个众所周知的基本原理。
同样,所有这些都是语言所要求的,它与数字在机器等中的表示方式完全无关,以及哪些位存储在哪里。
答案 3 :(得分:0)
无论底层表示(两个补码是最流行的,但是一个补码和符号幅度是其他),如果将-1转换为无符号类型,您将获得可以在该类型中表示的最大数字。
原因是无符号'溢出'行为被严格定义为通过模运算将值转换为0和该类型的最大值之间的数字。基本上,如果该值大于最大值,则重复减去最大值,直到您的值在范围内。如果您的值小于最小值(0),则重复添加最大值,直到它在范围内。因此,如果我们假设一个32位size_t
,则从-1开始,小于0.因此,你添加2 ^ 32,给你2^32 - 1
,这是在范围内,所以这是你的最终价值。
粗略地说,C ++定义了这样的促销规则:无论签名如何,任何类型的char
或short
都会首先提升为int
。比较中的较小类型被提升到比较中的较大类型。如果两个类型的大小相同,但其中一个是有符号的,而另一个是无符号的,则签名类型将转换为无符号。这里发生的事情是,您的rebuildIndex
正在转换为无符号size_t
。 1
转换为1u
,0
转换为0u
,-1
转换为-1u
,转换为无符号类型时是size_t
类型的最大值。