编辑:修改void *为uint8_t *值。问题仍然存在。编辑:问题是一个简单的变量溢出,与整数促销无关。
我解决了这段简化代码中的错误。类型与原始源代码中的类型相同。
unsigned int entrySize; // entrySize is 288
int startIndex, endIndex; // both are 24536838
uint8_t *pStartAddr; // valid initialized pointer (0x34f1e40)
/*Mystery begins...*/
uint8_t *curr_addr = pStartAddr + entrySize * startIndex;
while (curr_addr <= startAddr + entrySize * endIndex)
{
externFunc(curr_addr);
curr_addr+=entrySize;
}
快速浏览一下,这段代码看起来很明显,不包括奇怪的类型选择。
然而,在我们的一次崩溃中,似乎curr_addr
获得了无效的指针。我的预感是entrySize * startIndex
存在问题,因为它们的乘法设置在第32位,并且将startIndex
和endIndex
作为带符号类型可能会混淆编译器使用所需的值。
在更改了unsigned long类型后,问题就解决了。但我无法弄清楚到底出了什么问题。
我正在开发64位机器,x86_64 CPU,gcc(GCC)4.8.5 20150623和linux red hat distribution(版本4.8.5-28)
我假设当上面的计算设置在entrySize * startIndex
的第32位时问题开始发生。但是,当我使用第一个打开第32位的startIndex
值时,它仍然有效。它也显示出来了
我的问题是:
int
* unsigned int
被认为是签名或未签名的价值结果?结果类型的等级是多少?乘法可能会溢出到8字节类型,我认为编译器可以防止丢失精度,对吧?startAddr
是一个void*
。然后将其添加到第一个问题中计算的任何值和类型。 void*
被认为是signed
还是unsigned
?我的预感当然是一个unsigned
value
,但我不能支持它。我读了那些链接中包含的内容,但仍然无能为力:
乘法可能会溢出到8字节类型,我认为编译器可以防止丢失精度,对吧?
这是一个非常不正确的假设。 Per the 3.4.3 description of undefined behavior from the C standard(bolding mine):
3.4.3
1使用不可移植或错误的程序结构或错误数据时的未定义行为行为,本国际标准不对此要求
2注意可能的未定义行为包括完全忽略不可预测的结果,在转换或程序执行期间以环境特征(有或没有发出诊断消息)的方式执行,终止翻译或执行(带有发出诊断信息)。
3示例未定义行为的示例是整数溢出的行为。
整数溢出是C标准本身使用的未定义行为的一个例子。
288 * 24536838
等于7066609344
,它远远超出了32位int
的能力,无论是signed
还是unsigned
,从而引发了未定义的行为。
所以不,编译器不会“防止丢失精度”。事实恰恰相反。
void*
上的行为是未定义的。(1)在你的代码中肯定没有遵守(你的编译器没有警告你 - 如果不是,请把它装箱),(2)可能不是。那时(我本人)有点讽刺,你的具体问题是不相关的。