从有符号/无符号字符到无符号/有符号整数类型转换的 IA32 汇编代码

Posted

技术标签:

【中文标题】从有符号/无符号字符到无符号/有符号整数类型转换的 IA32 汇编代码【英文标题】:IA32 Assembly code for type casting from signed/unsigned char to unsigned/signed int 【发布时间】:2020-06-11 06:28:48 【问题描述】:

这是从计算机系统,程序员的角度来看(第 2 版)

在问题 3.4 中,要求学生确定从源数据类型转换到指针所指的目标所需的汇编指令

本章后面给出的这个答案表明我们需要将源类型(左列)扩展为目标类型(中列)。

没有太多信息可以从这个问题中得出一个模式。扩展的类型是否总是由源类型而不是目标类型决定,如本例所示?

【问题讨论】:

这是什么语言?我所知道的同时拥有charunsigned char 的唯一HLL 是C 和C++,这对那些人来说是错误的。对于 most 中的整数类型,x 是有符号的,unsigned x 是无符号的(可能在位域中使用时除外),但对于 char,符号是依赖于实现的,这意味着(如标准)它可能会有所不同,但必须记录在案。 C的这部分是由C++复制的。 教科书只使用C 【参考方案1】:

答案就在你的书中。

执行同时涉及大小更改和更改的演员表时 对于 C 中的“签名”,操作应首先更改大小。 (第 2.2.6 节)。

-- CSAPP 2e,练习题 3.4

所以这两个转换是这样工作的:

char --> int --> unsigned int
unsigned char --> unsigned int --> int

【讨论】:

在 C 中,由于 整数提升 规则会发生大小变化,然后应用转换。所以,首先unsigned char --> int 然后应用演员表。将unsigned char 扩大到int 意味着零扩展,以便表示更广泛的int 类型中的所有值。【参考方案2】:

扩展的类型是否总是由源类型而不是目标类型决定,就像这个例子一样?

是的。

强制转换保留由原始位表示的 (如果可能)。规则由此而来,因此这是让您思考为什么其他所有内容的关键概念就是这样。

如果它是无符号的,您可以通过在左侧填充零来使其更宽。 (零扩展名:movzx,AT&T movzbl / movzwl / movl(x86-64 上的 dword 到 qword)) 如果已签名,您可以通过填充符号位的副本来使其更宽。 (2's complement sign extension1movsx,或 AT&T movsbl / movswl / movsb/wq) 对于任何值,只需截断即可使其变窄 (从内存中读取低字节,或者更窄的部分寄存器)

做任何其他事情都不会保值。例如对于窄无符号 -> 宽有符号,宽类型可以表示窄类型的所有可能值。结果必须是非负的,因此符号位必须为零。 除了符号位,2 的补码和无符号二进制位值是相同的。 所以零扩展有效。例如192 作为 uint8_t192 作为 int 相同,但在 int 的左侧有更多的零位。

根据 ISO C11 (n1570),转换规则非常合理,并且与您的教科书显示的内容相匹配:

6.3 转化

6.3.1.3 有符号和无符号整数

    当整数类型的值转换为_Bool以外的其他整数类型时,如果该值可以用新类型表示,则 没有改变。 否则,如果新类型是无符号的,则通过重复加或减一的最大值来转换该值 可以用新类型表示,直到值在 新类型.60) 否则,新类型是有符号的,值不能在其中表示;结果是实现定义的或 引发了实现定义的信号。

对于第 2 点,请注意“就好像通过重复加或减 MAX_INT 一样”(对于 2 的补码)等同于简单地将位模式重新解释为有符号。即将 int 转换为 unsigned 不需要 asm 操作,您只需 mov 或更好地读取该值已经存在的任何寄存器或内存。

更多细节:无符号类型不能表示负值,因此这是一种情况,即使负输入更窄,它也不能为负输入“保值”。您可以将其视为逻辑符号扩展为等宽有符号类型(可以表示值),然后转换为无符号(只是重新解释相同的位,即扩大转换后没有额外的 asm 指令)。


脚注 1:x86 使用 2 的补码,其他所有相关内容也是如此。 C++ 甚至考虑放弃使用符号/幅度或 1 的补码整数的实现选项。


另请注意,教科书的答案使用了movz/sbl 的不可编码形式。它们仅适用于注册目的地。 movzbl %al, %ebx 可以,movzbl (%esi), %ebx 也可以,但movzbl %al, (%ebx)不是可以的。

也相关:

https://www.felixcloutier.com/x86/movzx / * https://www.felixcloutier.com/x86/movsx MOVZX missing 32 bit register to 64 bit register What does cltq do in assembly? - Intel 与 AT&T movsb/w 的等效表,以及特殊情况 AX->EAX 和类似指令。

【讨论】:

以上是关于从有符号/无符号字符到无符号/有符号整数类型转换的 IA32 汇编代码的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Rust 中将有符号整数添加到无符号整数,检查无符号溢出?

一元减号和有符号到无符号的转换

byte[] 到无符号 BigInteger?

C中的有符号到无符号转换 - 它总是安全的吗?

如何以优雅有效的方式将无符号/有符号整数/长整数转换为 C 字符串?

字符到无符号字符