我正在读这本书:CS-APPe2.C具有unsigned和signed int类型,并且在大多数体系结构中使用二进制补码算法来实现有符号值; 但在学习了一些汇编代码后,我发现很少有指令区分无符号和有符号.所以我的问题是:
编译器是否有责任区分已签名和未签名?如果是的话,它是如何做到的?
谁实现了二进制补码算法 - CPU或编译器?
添加更多信息:
在学习了一些更多的指令之后,实际上有一些指令区分了有符号和无符号,例如setg,seta等.此外,CF和OF分别适用于无符号和.但大多数整数算术指令对待无符号并且签名相同,例如
int s = a + b
Run Code Online (Sandbox Code Playgroud)
和
unsigned s = a + b
Run Code Online (Sandbox Code Playgroud)
生成相同的指令.
那么在执行时ADD s d,CPU是否应该对s&d进行未签名或签名?或者它是无关紧要的,因为两个结果的位模式是相同的,编译器的任务是将基础位模式结果转换为unsigned或signed?
PS我正在使用x86和gcc
在许多情况下,在有符号和无符号操作之间的机器级别上没有区别,并且仅仅是对位模式的解释.例如,考虑以下4位字操作:
Binary Add Unsigned 2's comp
---------- -------- --------
0011 3 3
+ 1011 + 11 - 5
------- -------- --------
1110 14 -2
------- -------- --------
Run Code Online (Sandbox Code Playgroud)
对于有符号和无符号操作,二进制模式是相同的.请注意,减法仅仅是添加负值.当执行SUB操作时,右手操作数是两个补码(反转位和增量)然后相加(负责的ALU电路是加法器); 不是你理解的指令级别,而是在逻辑级别,尽管可以实现没有SUB指令的机器,并且仍然执行减法,尽管是在两个指令而不是一个指令中.
根据类型的不同,有些操作需要不同的指令,编译器通常负责生成适当的代码 - 架构变体可能适用.
这很容易。加法和减法等运算不需要对二进制补码算术中的有符号类型进行任何调整。只需进行一个思维实验并想象一个仅使用以下数学运算的算法:
加法只是从一个堆中逐个取出项目并将它们放入另一个堆中,直到第一个堆为空。减法就是同时对两者进行减法,直到减掉的那个为空。在模算术中,您只需将最小值视为最大值加一即可。二进制补码只是一种模运算,其中最小值为负数。
如果您想看到任何差异,我建议您尝试在溢出方面不安全的操作。一个例子是比较( a < b)。
编译者有责任区分签名和未签名吗?如果是,它是如何做到的?
通过在需要时生成不同的程序集。
谁实现补码运算——CPU 还是编译器?
这是一个很难的问题。二进制补码可能是计算机中处理负整数的最自然的方式。带有溢出的二进制补码的大多数操作与带有溢出的无符号整数的操作相同。可以从单个位中提取符号。从概念上讲,比较可以通过减法(与符号无关)、符号位提取和与零比较来完成。
不过,CPU 的算术功能允许编译器以二进制补码进行计算。
无符号 s = a + b
请注意,此处计算 plus 的方式不依赖于结果的类型。相反,它取决于等号右侧变量的类型。
那么执行ADD sd时,CPU应该对待s&d无符号还是有符号呢?
CPU 指令不知道类型,这些指令仅由编译器使用。此外,两个无符号数相加和两个有符号数相加没有区别。对于同一个操作使用两条指令是很愚蠢的。