char数据类型在32位寄存器中是如何表示的?

问题描述 投票:0回答:6

我知道

int
和其他 32 位数据类型适合寄存器。但是,我不明白当我们的数据类型(例如 1 字节的
char
)小于 32 位时会发生什么。就像
char
的例子一样,剩下的 24 位会怎样?是否用全 0 填充?是不是太小了,无法用一个词来表达?


假设我有一个带有

char
变量的 C 程序。它在寄存器中如何表示?

c char cpu-registers
6个回答
2
投票

如果CPU允许分段寄存器访问(例如字、字节),它可能只使用字节子寄存器。 如果 CPU 严格为 32 位,则您的字节将进入位 0-7。 根据目标的使用情况,如果目标代码与寄存器一起工作,它可能会也可能不会将其余部分屏蔽为 0。(AND reg,0x000000FF)。 有太多的变数和太多的开放性,无法给你一个非黑即白的答案。

使用 0xFF 作为字节寄存器和 0x000000FF 作为 d 字寄存器与使用它们的操作码相同(如果它们具有单独的字节和双字对应部分)。 除非它们是特定于位的操作,例如“如果设置了高位则分支”或位旋转/移位。 如果有符号,0xFF 将扩展为 0xFFFFFFFF(或 0x83 扩展为 0xFFFFFF83)

编辑更新:表示寄存器中的字符的 C 确实会将其余部分清零,具体取决于编译器,它可能会在设置位 0-7 之前先将寄存器清零,或者可能会按照上面的说明执行。 当有符号时,符号位需要扩展寄存器为 0,对其求反并设置 0-7。 有些 CPU 甚至有一个明确的符号扩展操作。


1
投票

一般来说,无符号数量用零填充,有符号数量是符号扩展

C 中的

char
类型是一种特殊情况,因为标准允许它是有符号的或无符号的(并且一些编译器提供了一个选项让开发人员选择)。 这允许编译器使用最有效的那个。


0
投票

这取决于它如何放置在那里。 对于容器来说,数据永远不会“太小”。


0
投票

字符受到整数提升的影响。一旦它们与其他非 char 整数值组合,它们就会被符号扩展为

int
,如果它们与此类操作数组合,甚至是浮点数。

您有责任确保不会不当使用结果。当您将

int
转换为
char
时,您就隐含地接受了丢失高位有效位的风险。

至于特定编译器如何处理它,则取决于编译器设计者。在 Pentium 巨大的架构中,您可以使用寄存器的 char 版本,但在更传统的处理器上,如果涉及进一步的计算,对 char 进行符号扩展以标准化其值可能会更方便。


0
投票

C 语言没有寄存器,因此没有程序员可见的表示形式。如果使用更宽寄存器的一部分,则未使用的部分可能包含其他数据,或者可能包含零。重要的是操作

char
值(或任何其他)的正确程序被正确翻译,以便产生正确的输出和任何其他外部可见的行为。

如果使用 32 位寄存器来保存 8 位字符,并且未清除未使用的位,则生成的机器代码必须小心,例如,不要将剩余的 24 位涉及到像

(char_a == char_b) 所产生的比较中
,因为两个相等的
char
会错误地比较不相等。生成的机器代码必须告诉处理器使用一些仅查看最低有效 8 位的字节宽操作。某些架构具有此类功能,因此可能更容易生成将内存中的
char
表示形式转换为寄存器中完整 32 位值的代码(如果有符号,则进行符号扩展)。

这实际上取决于给定目标处理器上什么是方便和高效的。


0
投票

在 x86 上,子寄存器有单独的硬件名称。 eax 的下部是 al。您甚至可以在同一个寄存器上分配 2 个字符:eax 是 [16 位 |啊|等]。因此可以通过 al/ah/bl/bh 等处理高位中有垃圾的字符。但 gcc 更喜欢执行非常奇怪的事情:

char foo(char c) {
    return c+(char)1;
}

gcc -O2 -m32 -S:

foo:
    pushl   %ebp
    movl    %esp, %ebp
    movzbl  8(%ebp), %eax
    popl    %ebp
    addl    $1, %eax
    movsbl  %al,%eax
    ret

movzbl 表示用零扩展,movsbl 表示用符号位扩展。

第一次用 0 扩展输入,然后执行 +1,然后用低字节 (al) 符号位扩展结果 (eax)。因此它同时使用零/符号位扩展。对于无符号字符,零叶值相同,对于有符号字符,符号位相同。

© www.soinside.com 2019 - 2024. All rights reserved.