定义如何存储换档操作的临时结果是C标准吗?

时间:2014-03-17 06:02:42

标签: c standards bit-shift c11

我的C程序非常简单,可以在64位Linux中运行:

#include <stdio.h>
int main(void)
{
    unsigned char a = 0xff;
    unsigned  short b = (a << 6) ;
    return 0;
}

我很好奇(&&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&quot;&#6)的临时结果存储在哪里

0x0000000000400474 <+0>:     push   %rbp
0x0000000000400475 <+1>:     mov    %rsp,%rbp
0x0000000000400478 <+4>:     movb   $0xff,-0x3(%rbp)
0x000000000040047c <+8>:     movzbl -0x3(%rbp),%eax
0x0000000000400480 <+12>:    shl    $0x6,%eax
0x0000000000400483 <+15>:    mov    %ax,-0x2(%rbp)
0x0000000000400487 <+19>:    mov    $0x0,%eax
0x000000000040048c <+24>:    leaveq
0x000000000040048d <+25>:    retq

从汇编代码中,我可以看到eax用于存储班次操作的临时结果。

所以我想知道使用有符号/无符号32位整数来存储移位操作的临时结果是C标准吗?

我已检查n1570 specification6.5.7 按位移位运算符,但找不到任何内容。

4 个答案:

答案 0 :(得分:5)

标准没有指定那些低级详细信息,但是您错过了the draft C11 standrd部分6.5.7 2 中的一个重要部分(强调我的 >):

  

对每个操作数执行整数提升。[...]

部分6.3.1 算术操作数小节6.3.1.1 布尔,字符和整数 2 其中说:

  

在int或unsigned int可以的任何地方都可以使用以下代码   使用:

并包含以下项目符号:

  

具有整数类型的对象或表达式(int或unsigned int除外)   其整数转换等级小于或等于int和的等级   unsigned int。

包括简短 char 并接着说(强调我的):

  

如果int可以表示原始类型的所有值(由宽度限制,对于a   bit-field),将值转换为int;否则,它将转换为无符号   INT。 这些称为整数促销。 58) 所有其他类型均未被   整数促销。

因此,a6都必须提升为 int ,这将提供一个下限,可以使用哪个寄存器来存储中间结果。

注意,正如Keith在您的代码示例中指出的那样,因为赋值和移位没有可观察的行为,编译器可以自由地优化这些指令。

答案 1 :(得分:3)

C编译器可以将结果存储在任何喜欢的位置:您将a指定为char(通常为8位),将b指定为short int(通常为16位),它们都很容易适合32位%eax

如果将ab定义为long long int(64位),您将注意到编译器必须使用64位寄存器(例如%rax)。< / p>

答案 2 :(得分:3)

标准仅指定C程序的可观察行为。由于你的程序没有,编译器完全有权用nop或几乎任何没有可观察到的副作用的东西替换它。

但是,通常小于int的积分表达式的操作数被提升为int或其他操作数类型,以较大者为准。

答案 3 :(得分:0)

实际上,对于移位操作,C标准要求将操作数符号扩展为int,进行计算并截断结果(如果需要)。如果它得到相同的结果,它只能省略它。

这就是为什么即使挑选编译器也不会发出警告,如果你移动一个超过7位的字符(尝试它 - 只有当你移动宽度大于允许时才会得到警告)。 / p>