- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
C 语言有符号和无符号类型,如 char 和 int。我不确定它是如何在汇编级别实现的,因为例如,在我看来,有符号和无符号的乘法会带来不同的结果,所以汇编都做无符号的和带符号的算术或只有一个,这在某种程度上模拟不同的情况?
最佳答案
如果你看x86的各种乘法指令,只看32位的变体而忽略BMI2,你会发现这些:
imul r/m32
(32x32->64 有符号乘法)imul r32, r/m32
(32x32->32 乘法)*imul r32, r/m32, imm
(32x32->32 相乘)*mul r/m32
(32x32->64 无符号乘法)请注意,只有“扩大”乘法具有无符号的对应项。中间标有星号的两种形式,都是有符号和无符号的乘法,因为如果你没有得到额外的“上半部分”,那是一回事。 p>
“扩大”乘法在 C 语言中没有直接等价物,但编译器无论如何都可以(而且经常这样做)使用这些形式。
例如,如果你编译这个:
uint32_t test(uint32_t a, uint32_t b)
{
return a * b;
}
int32_t test(int32_t a, int32_t b)
{
return a * b;
}
使用 GCC 或其他一些相对合理的编译器,你会得到这样的东西:
test(unsigned int, unsigned int):
mov eax, edi
imul eax, esi
ret
test(int, int):
mov eax, edi
imul eax, esi
ret
(使用 -O1 的实际 GCC 输出)
因此符号性对于乘法(至少对于您在 C 中使用的那种乘法而言不是)和其他一些操作无关紧要,即:
x86 不为这些提供单独的签名/未签名版本,因为无论如何都没有区别。
但对于某些操作是有区别的,例如:
idiv
与 div
)idiv
与 div
)sar
vs shr
)(但要注意 C 语言中的有符号右移)但最后一个很特别,x86 也没有单独的有符号和无符号版本,而是只有一个操作(cmp
,它实际上只是一个非破坏性的 sub
) 同时执行这两项操作,并给出多个结果(“标志”中的多个位受到影响)。实际使用这些标志的后续指令(分支、条件移动、setcc
)然后选择它们关心的标志。例如,
cmp a, b
jg somewhere
如果 a
的“符号大于”b
,将去某处
。
cmp a, b
jb somewhere
如果 a
是“下面未签名的”b
,将去某处
。
参见 Assembly - JG/JNLE/JL/JNGE after CMP有关标志和分支的更多信息。
这不是有符号乘法和无符号乘法相同的正式证明,我只是试图让您深入了解为什么它们应该相同。
考虑 4 位 2 的补码整数。它们各个位的权重,从 lsb 到 msb,1、2、4 和 -8。当你将这些数字中的两个相乘时,你可以将其中一个分解为对应于它的位的 4 个部分,例如:
0011 (decompose this one to keep it interesting)
0010
---- *
0010 (from the bit with weight 1)
0100 (from the bit with weight 2, so shifted left 1)
---- +
0110
2 * 3 = 6 所以一切都检查出来了。这只是大多数人在学校学习的常规长乘法,只有二进制,这使得它变得容易得多,因为你不必乘以十进制数字,你只需要乘以 0 或 1,然后移位。
无论如何,现在取一个负数。符号位的权重是 -8,所以在某个时候你会得到一个部分乘积 -8 * something
。 8 的乘法是左移 3,所以之前的 lsb 现在是 msb,所有其他位都是 0。现在如果你否定它(毕竟是 -8,而不是 8),什么也不会发生。零显然没有变化,但8也是如此,一般只设置了msb的数字:
-1000 = ~1000 + 1 = 0111 + 1 = 1000
因此,如果 msb 的权重为 8(如在无符号情况下)而不是 -8,那么您所做的事情与您所做的相同。
关于c - x86 上的有符号和无符号算术实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25241477/
问题故障解决记录 -- Java RMI Connection refused to host: x.x.x.x .... 在学习JavaRMI时,我遇到了以下情况 问题原因:可
我正在玩 Rank-N-type 并尝试输入 x x .但我发现这两个函数可以以相同的方式输入,这很不直观。 f :: (forall a b. a -> b) -> c f x = x x g ::
这个问题已经有答案了: How do you compare two version Strings in Java? (31 个回答) 已关闭 8 年前。 有谁知道如何在Java中比较两个版本字符串
这个问题已经有答案了: How do the post increment (i++) and pre increment (++i) operators work in Java? (14 个回答)
下面是带有 -n 和 -r 选项的 netstat 命令的输出,其中目标字段显示压缩地址 (127.1/16)。我想知道 netstat 命令是否有任何方法或选项可以显示整个目标 IP (127.1.
我知道要证明 : (¬ ∀ x, p x) → (∃ x, ¬ p x) 证明是: theorem : (¬ ∀ x, p x) → (∃ x, ¬ p x) := begin intro n
x * x 如何通过将其存储在“auto 变量”中来更改?我认为它应该仍然是相同的,并且我的测试表明类型、大小和值显然都是相同的。 但即使 x * x == (xx = x * x) 也是错误的。什么
假设,我们这样表达: someIQueryable.Where(x => x.SomeBoolProperty) someIQueryable.Where(x => !x.SomeBoolProper
我有一个字符串 1234X5678 我使用这个正则表达式来匹配模式 .X|..X|X. 我得到了 34X 问题是为什么我没有得到 4X 或 X5? 为什么正则表达式选择执行第二种模式? 最佳答案 这里
我的一个 friend 在面试时遇到了这个问题 找到使该函数返回真值的 x 值 function f(x) { return (x++ !== x) && (x++ === x); } 面试官
这个问题在这里已经有了答案: 10年前关闭。 Possible Duplicate: Isn't it easier to work with foo when it is represented b
我是 android 的新手,我一直在练习开发一个针对 2.2 版本的应用程序,我需要帮助了解如何将我的应用程序扩展到其他版本,即 1.x、2.3.x、3 .x 和 4.x.x,以及一些针对屏幕分辨率
为什么案例 1 给我们 :error: TypeError: x is undefined on line... //case 1 var x; x.push(x); console.log(x);
代码优先: # CASE 01 def test1(x): x += x print x l = [100] test1(l) print l CASE01 输出: [100, 100
我正在努力温习我的大计算。如果我有将所有项目移至 'i' 2 个空格右侧的函数,我有一个如下所示的公式: (n -1) + (n - 2) + (n - 3) ... (n - n) 第一次迭代我必须
给定 IP 字符串(如 x.x.x.x/x),我如何或将如何计算 IP 的范围最常见的情况可能是 198.162.1.1/24但可以是任何东西,因为法律允许的任何东西。 我要带198.162.1.1/
在我作为初学者努力编写干净的 Javascript 代码时,我最近阅读了 this article当我偶然发现这一段时,关于 JavaScript 中的命名空间: The code at the ve
我正在编写一个脚本,我希望避免污染 DOM 的其余部分,它将是一个用于收集一些基本访问者分析数据的第 3 方脚本。 我通常使用以下内容创建一个伪“命名空间”: var x = x || {}; 我正在
我尝试运行我的test_container_services.py套件,但遇到了以下问题: docker.errors.APIError:500服务器错误:内部服务器错误(“ b'{” message
是否存在这两个 if 语句会产生不同结果的情况? if(x as X != null) { // Do something } if(x is X) { // Do something } 编
我是一名优秀的程序员,十分优秀!