了解C中的积分算术

Avi*_*viv 2 c types integer-overflow

编辑:将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;
}
Run Code Online (Sandbox Code Playgroud)

乍一看,此代码似乎很明显,不包括奇怪的类型选择。

但是,在我们的一次崩溃中,似乎curr_addr获得了无效的指针。我的直觉是存在一个问题,entrySize * startIndex因为它们的乘法设置在第32位,并且具有startIndexendIndex作为符号类型可能会使编译器使用所需的值感到困惑。

在更改了他们的类型之后,问题就解决了。但我无法弄清楚到底是什么问题。

我正在使用64位计算机,x86_64 CPU,gcc(GCC)4.8.5 20150623和linux red hat发行版(版本4.8.5-28)

我以为上面的计算在的第32位设置时开始出现问题entrySize * startIndex。但是,当我使用第startIndex32位打开的第一个值时,它仍然有效。它也显示

我的问题是:

  • int* 的值结果unsigned int是带符号的还是无符号的?结果类型的等级是多少?乘法可能溢出到8个字节类型,我认为编译器可以防止精度下降,对吗?
  • startAddr是一个void*。然后将其添加到第一个问题中计算出的任何值和类型。被void* 认为signed还是unsigned?我的直觉当然是unsigned value,但是我无法备份它。
  • Integer促销在startAddr + << 结果 >>中进行。
  • 我们的while语句可以在实际时间内永不停止吗?如果不等式的右边是带符号的数字(宽度至少为8个字节),那么左侧(curr_addr)是否也会被提升为带符号的数字,从而导致无限循环?
  • 一步一步的解释将是最欢迎的:)

我阅读了那些链接中包含的内容,但仍然一无所知:

  1. https://www.oreilly.com/library/view/c-in-a/0596006977/ch04.html
  2. 有符号和无符号int的整数转换等级

Bat*_*eba 5

  1. 指针算术在a上的行为void*是不确定的。

  2. 指针算术仅在数组内有效。请注意,您可以指针设置为指向数组最后一个元素之后的指针,但不要尝试取消引用它。此规则也适用于对象,出于规则的目的,这些对象可以视为单元素数组。

(1)当然不会在您的代码中服从(您的编译器不会警告您-如果没有,请对它进行装箱),(2)可能不会。那时(在我看来)有些滑稽,您的特定问题无关紧要。

  • “在void *上的指针算术行为是不确定的”甚至还不是,这是一个约束冲突,意味着它不能干净地编译。C17分别为6.5.5和6.5.6。 (2认同)