编辑:将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
作为有符号类型可能会使期望值的编译器混淆使用。
在更改其类型后,问题就解决了。 但我无法弄清楚完全是什么错误。
我正在使用64位计算机,x86_64 CPU,gcc(GCC)4.8.5 20150623和linux red hat发行版(版本4.8.5-28)
我假设当以上计算在entrySize * startIndex
的第32位上设置时,问题开始出现。但是,当我使用第32位打开的第一个startIndex
值时,它仍然有效。它也显示了
我的问题是:
int
* unsigned int
的值结果,被认为是带符号或
未签名?结果类型的等级是多少?乘法可以
可能溢出到8个字节类型,我认为编译器会阻止
失去精度吧? startAddr
是void*
。然后添加
到第一个问题中计算出的任何值和类型。是void*
被认为是signed
或unsigned
?我的直觉当然是unsigned
value
,但我不能支持它。我阅读了那些链接中包含的内容,但仍然一无所知:
答案 0 :(得分:5)
在void*
上的指针算术行为未定义。
指针算术仅在数组内有效。请注意,您可以设置指向数组最后一个元素之后的指针,但不要尝试取消引用它。此规则也适用于可以视为规则目的的单元素数组的对象。
(1)当然不会在您的代码中服从(编译器不会警告您-如果没有,请对它进行装箱),(2)可能不会。那时(在我看来)有些滑稽,您的特定问题无关紧要。
答案 1 :(得分:2)
乘法可能溢出到8个字节类型,我认为编译器可以防止精度下降,对吗?
那是一个严重错误的假设。每个the 3.4.3 description of undefined behavior from the C standard(正在轰动我):
3.4.3
1种不确定行为,使用不可移植或错误的行为 程序结构或错误数据,本国际 标准没有任何要求
2注意可能的不确定行为包括忽略情况 完全具有不可预测的结果,可以在翻译过程中表现 或以书面形式记录程序执行 环境(带有或不带有诊断消息), 终止翻译或执行(签发 诊断消息)。
3 示例未定义行为的一个示例是整数行为 溢出。
整数溢出是C标准本身使用的未定义行为的一个很好的例子。
并且288 * 24536838
等于7066609344
,远远超出了32位int
的容量,无论是signed
还是unsigned
,因此调用了undefined行为。
因此,不,编译器不会“防止精度下降”。实际上,恰恰相反。