这个问题与我目前看到的任何错误无关,更多的是关于理论并接受有关硬件架构设计和实现的变化的教育。
<小时/> 场景1:假设一个16位处理器具有16位寄存器,16位寻址和sizeof(int)= 16位:
unsigned int a, b, c, d;
a=0xFFFF;
b=0xFFFF;
c=a+b;
是否可以覆盖c
旁边的内存位置?
(在这种情况下,我希望在 add 操作期间会引发溢出标志,并且c
保持不变或填充未定义的数据。)
unsigned int a, b;
unsigned short int c, d;
a=0xFFFF;
b=0xFFFF;
c=a+b;
是否可以覆盖c
旁边的内存位置?
(我希望在add操作期间不会引发溢出标志,但是在赋值操作期间是否引发内存访问或溢出标志将取决于HW的实际设计和实现。如果{{ 1}}位于相同32位地址位置的高16位(可能甚至不能用32位寻址),它可能会被覆盖。)
d
是否可以覆盖unsigned int a, b;
unsigned short int c, d;
a=0xFFFF;
b=0xFFFF;
c=a+b;
旁边的内存位置?
(我希望在类型转换和赋值操作期间引发一些溢出标志或内存冲突标志。)
c
是否有可能覆盖unsigned int a, b;
struct {
unsigned int c:16;
unsigned int d:16;
} e;
a=0xFFFF;
b=0xFFFF;
e.c=a+b;
旁边的内存位置,即c
? (在这种情况下,由于d
和c
预期驻留在相同的32位地址中,并且两者都是技术上的32位整数,因此可以想象在添加或赋值期间不会引发溢出标志, d
可能会受到影响。)
答案 0 :(得分:4)
您的1,2,3,4都不会导致任何内存损坏,或者为正在执行算术运算的整数位置写入“过去”存储。 C指定无符号整数溢出时应该发生什么。这是假设编译器生成它应该的代码。没有什么可以保护您使用错误的编译器来生成将4个字节复制到2字节变量中的代码。
以下是C99(6.2.5)所说的内容:
“涉及无符号操作数的计算永远不会溢出, 因为无法用结果无符号整数类型表示的结果是 减少模数可以是最大值的数字 由结果类型表示。“
因此,很好地定义了当您尝试“溢出”无符号整数时会发生什么。
现在,如果您的整数已经签名整数,那么这是另一个故事。根据C,溢出有符号整数会导致未定义的行为。未定义的行为意味着可能发生任何事情,包括内存损坏。我还没有看到一个C编译器会破坏有关溢出整数的任何内容。
典型处理器使用哪些设备来防止相邻内存被算术和赋值操作覆盖?
在分配和算术运算方面没有防止相邻内存的保护。处理器只是执行给它的机器代码指令(如果这些指令覆盖了内存,那么就不会像更高级语言那样表达,处理器也不在乎)。
稍微不同的级别,如果CPU无法执行操作(例如,操作指定的内存位置不存在),或者尝试执行某些非法操作(例如,除以零),CPU可能会发出traps ,或遇到处理器无法理解的操作码,或尝试对数据进行未对齐访问。)
答案 1 :(得分:1)
添加操作在处理器内部处理,所以无论你做什么,添加操作都将在CPU内完成(在ALU中更精确) 溢出寄存器将在溢出时置1,结果仍然在寄存器中,然后复制回存储器位置,而不会损坏相邻存储器。 这就是代码将如何(在某种程度上)转换为asm:
mov ax, ptr [memory location of a]
mov bx, ptr [memory location of b]
add ax,bx
mov ptr [memory location of c], ax
所以你可以看到,无论是否发生溢出,c都只能保存ax(具有已知和固定大小)的内容
答案 2 :(得分:1)
在C中,使用无符号类型的溢出行为是明确定义的。任何溢出导致除标准预测之外的任何结果都不符合的实现。
未定义带有签名类型的溢出行为。虽然溢出的最常见影响可能是分配一些错误值或彻底崩溃,但C标准中没有任何内容可以保证处理器不会以编译代码尝试从中恢复的方式触发溢出错误,但由于某种原因,它会破坏堆栈变量或寄存器的内容。溢出也可能导致标志以代码不期望的方式设置,并且这样的标志可能会在将来的计算中导致错误的行为。
其他语言在发生溢出时可能会有不同的语义。
注意:我已经看到处理器在溢出时陷阱,处理器中与外部中断同时发生的意外陷阱可能导致数据损坏,而处理器中出现意外的无符号溢出可能导致后续计算被关闭一。我不知道有没有签名的溢出会锁定一个会干扰后续计算的标志,但是有些DSP有一些有趣的溢出行为,所以如果存在,我不会感到惊讶。