【问题标题】:How does char data type represent in 32-bit registers?char 数据类型在 32 位寄存器中如何表示?
【发布时间】:2014-01-07 01:10:07
【问题描述】:

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

更新:假设我有一个带有 char 变量的 C 程序。它在寄存器中如何表示?

【问题讨论】:

  • gcc -S 可能会对你有所帮助。

标签: c char cpu-registers


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    一般情况下,无符号数量用零填充,有符号数量为sign-extended

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

    【讨论】:

      【解决方案3】:

      这取决于它是如何放在那里的。对于容器而言,数据永远不会“太小”。

      【讨论】:

        【解决方案4】:

        字符以integer promotion 为准。一旦它们与其他非字符整数值组合,它们就会被符号扩展为 int,如果它们与此类操作数组合,甚至是浮点数。

        您有责任确保您不会不当使用结果。当您将 int 回退为 char 时,您隐含地接受了丢失高位有效位的风险。

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

        【讨论】:

          【解决方案5】:

          C 语言没有寄存器,因此程序员看不到这样的表示。如果使用较宽寄存器的一部分,则未使用的部分中可能有其他数据,或者可能有零。重要的是,正确转换处理 char 值(或任何其他值)的正确程序,以便它产生正确的输出和任何其他外部可见的行为。

          如果使用 32 位寄存器来保存 8 位字符,并且未清除未使用的位,则生成的机器代码必须小心,例如,不要在比较中涉及剩余的 24 位,例如(char_a == char_b),因为这样两个相等的chars 会错误地比较不相等。生成的机器代码必须告诉处理器使用一些只查看最低有效 8 位的字节宽操作。一些体系结构有这种东西,因此生成将内存中的char 表示形式转换为寄存器中的完整 32 位值的代码可能更容易(符号扩展,如果它们是有符号的)。

          这真的取决于给定目标处理器的方便和高效。

          【讨论】:

            【解决方案6】:

            在 x86 上,子寄存器有单独的硬件名称。 eax的下半部分是al。您甚至可以在同一个寄存器上分配 2 个字符: eax 是 [16 bits |啊 |人]。因此,可以通过 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)。所以它同时使用零/符号位扩展。零对于无符号字符的值相同,对于有符号字符的符号位。

            【讨论】:

              猜你喜欢
              • 2014-11-18
              • 2020-10-29
              • 1970-01-01
              • 1970-01-01
              • 2020-11-21
              • 2010-12-04
              • 1970-01-01
              • 2010-09-15
              相关资源
              最近更新 更多