PIC 中的整数溢出——流到哪里去了?
使用 Microchip 18f4620 PIC。不过,这应该是一个标准的 ANSI C 问题。
假设我有
unsigned int16 badFlow=65535 //max unsigned int16 value
This 的二进制值为 1111 1111 1111 1111
。
如果我那么
badFlow++;
位模式变为 1 0000 0000 0000 0000
17 位。显然 badFlow == 0
,但是额外的翻转位要么
- 被丢弃
- ,要么驻留在
byte* flowPtr = &badFlow+2;
的任何位置 点。
我假设是后者,但希望是前者。
我的问题:一位同事编写了一些错误的代码,其计数器在所有生产的产品上溢出了大约 2 年。考虑到我们的客户使用这些工具的费用,由于潜在的不良数据,这将带来数百万美元的危险。
Working with a Microchip 18f4620 PIC. This should be a standard ANSI C question, though.
Say I have
unsigned int16 badFlow=65535 //max unsigned int16 value
This has a binary value of 1111 1111 1111 1111
.
if I then
badFlow++;
the bit pattern becomes 1 0000 0000 0000 0000
17 bits. Obviously badFlow == 0
, but the additional flipped bit either
- gets discarded
- or resides at wherever
byte* flowPtr = &badFlow+2;
points.
I'm assuming the latter, but hoping for the former.
My problem: a coworker has written some bad code with a counter that has been overflowing on all produced products for ~2 years. Considering what our customers charge for use of these tools, that's a few million dollars in peril due to potentially bad data.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
C 中的算术使用值进行,而不是内存中的字节。您的表达式
badFlow++
相当于badFlow = badFlow + 1
。右侧被评估为类型int
(由于默认提升,假设int
大于 16 位;如果int
仅是 16位,那么它将被评估为unsigned int
),结果为 65536,然后当 65536 被分配给无符号 16 位变量时,它会以 65536 为模进行减少,从而得到0.从这个答案中得到的重要一点是,
badFlow++
不是对&badFlow
处内存的直接操作(尽管它可能实现)在某些实现上也是如此)。它只是加法和赋值的简写。Arithmetic in C takes place with values, not bytes in memory. Your expression
badFlow++
is equivalent tobadFlow = badFlow + 1
. The right-hand side is evaluated as typeint
(due to default promotions, assumingint
is larger than 16 bits; ifint
is only 16 bits then it would be evaluated asunsigned int
) resulting in 65536, then when 65536 is assigned into an unsigned 16-bit variable, it is reduced modulo 65536, resulting in 0.The important thing to get out of this answer is that
badFlow++
is not a direct operation on the memory at&badFlow
(although it could possibly be implemented as such on some implementations). It's simply shorthand for an addition and assignment.最高有效数字被丢弃。许多处理器都有一个状态寄存器,指示发生了溢出,但从 C 中看不到(您必须在汇编中工作才能使用它)
The most significant digit gets discarded. Many processors will have a status register that indicates that an overflow occurred, but that is not visible from C (you'd have to work in assembly to use it)
它不会溢出到
badFlow
之后的内存中。It will not overflow into memory that follows
badFlow
.选项1是正确的,溢出被默默丢弃。
Option 1 is correct, the overflow is silently discarded.
标准 C 中整数类型的上溢或下溢通常是一种安全操作,并且不会修改超出所访问变量范围的内存。在标准 C 中,溢出位被丢弃,但实现可能会将其存储在特殊的溢出寄存器或专用内存位置中。例如,在 i386 系统上,溢出在“进位标志”中发出信号。
编辑:正如 @aix 指出的那样,进位标志并不是由每个相关的 i386 汇编指令更新的。这当然是一个实现细节; C 语言并没有对进位标志给予任何关注。
编辑2:正如 R. 指出的那样,签名溢出是未定义的行为,尽管我见过的每个实现仍然安全地对待它。
Overflowing or underflowing an integer type in standard C is generally a safe operation and will not modify memory beyond the bounds of the variable being accessed. In standard C, the overflow bit is discarded, though the implementation may store it in a special overflow register or dedicated memory location. For instance, on i386 systems, overflow is signalled in the "carry flag."
Edit: As @aix points out, the carry flag isn't updated by every relevant i386 assembly instruction. This is an implementation detail of course; the C language doesn't give two hoots about carry flags.
Edit 2: And as R. points out, signed overflow is undefined behaviour, though every implementation I've seen still treats it safely.
迁移到 uint32 并发布新的软件版本将是正确的方法。
Moving to
uint32
and making a new software release would be the right way to go..