理解 C 中的积分运算
Understanding of integral arithmetics in C
编辑:将 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
作为签名类型可能会使编译器混淆所需的值使用。
改成unsinged 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
,但我无法支持它。
- 在 startAddr + <<result>> 中进行了哪些整数提升。
- 我们的 while 语句可以永不停止吗(在实际时间内)?如果不等式右边是有符号数(宽度至少8字节),左边(curr_addr)是否也会被提升为有符号数,导致死循环?
- 欢迎逐步解释:)
我阅读了那些链接中包含的内容,但仍然一无所知:
- https://www.oreilly.com/library/view/c-in-a/0596006977/ch04.html
- Integer conversion rank of signed and unsigned int
void*
上的指针运算行为未定义。
指针算法只在数组中有效。请注意,您可以 设置 指向数组最后一个元素之后的指针,但不要尝试取消引用它。此规则也适用于可被视为单元素数组的对象。
(1) 在你的代码中肯定没有被遵守(你的编译器没有警告你 - 如果没有,将它装箱),(2)可能不是。有点滑稽(就我而言),你的具体问题不相关。
multiplication can probably overflow to 8 bytes types and I assume the compiler prevents losing precision, right?
这是一个严重错误的假设。每 the 3.4.3 description of undefined behavior from the C standard(加粗我的):
3.4.3
1 undefined behavior behavior, upon use of a nonportable or erroneous
program construct or of erroneous data, for which this International
Standard imposes no requirements
2 NOTE Possible undefined behavior ranges from ignoring the situation
completely with unpredictable results, to behaving during translation
or program execution in a documented manner characteristic of the
environment (with or without the issuance of a diagnostic message), to
terminating a translation or execution (with the issuance of a
diagnostic message).
3 EXAMPLE An example of undefined behavior is the behavior on integer
overflow.
整数溢出是 C 标准本身使用的未定义行为的典型例子。
而288 * 24536838
等于7066609344
,这远远超出了32位int
的容量,无论是signed
还是unsigned
,因此调用未定义的行为。
所以不,编译器不会"prevent losing precision"。事实上恰恰相反。
编辑:将 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
作为签名类型可能会使编译器混淆所需的值使用。
改成unsinged 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
,但我无法支持它。- 在 startAddr + <<result>> 中进行了哪些整数提升。
- 我们的 while 语句可以永不停止吗(在实际时间内)?如果不等式右边是有符号数(宽度至少8字节),左边(curr_addr)是否也会被提升为有符号数,导致死循环?
- 欢迎逐步解释:)
我阅读了那些链接中包含的内容,但仍然一无所知:
- https://www.oreilly.com/library/view/c-in-a/0596006977/ch04.html
- Integer conversion rank of signed and unsigned int
void*
上的指针运算行为未定义。指针算法只在数组中有效。请注意,您可以 设置 指向数组最后一个元素之后的指针,但不要尝试取消引用它。此规则也适用于可被视为单元素数组的对象。
(1) 在你的代码中肯定没有被遵守(你的编译器没有警告你 - 如果没有,将它装箱),(2)可能不是。有点滑稽(就我而言),你的具体问题不相关。
multiplication can probably overflow to 8 bytes types and I assume the compiler prevents losing precision, right?
这是一个严重错误的假设。每 the 3.4.3 description of undefined behavior from the C standard(加粗我的):
3.4.3
1 undefined behavior behavior, upon use of a nonportable or erroneous program construct or of erroneous data, for which this International Standard imposes no requirements
2 NOTE Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).
3 EXAMPLE An example of undefined behavior is the behavior on integer overflow.
整数溢出是 C 标准本身使用的未定义行为的典型例子。
而288 * 24536838
等于7066609344
,这远远超出了32位int
的容量,无论是signed
还是unsigned
,因此调用未定义的行为。
所以不,编译器不会"prevent losing precision"。事实上恰恰相反。