使用unsigned long long签名扩展

时间:2011-09-26 11:44:11

标签: c

我们发现了一些奇怪的值,下面是一个小测试用例。 这将打印“FFFFFFFFF9A64C2A”。这意味着无符号的长长似乎已被标记延长。 但为什么 ? 下面的所有类型都是无符号的,那么符号扩展的是什么?预期的产出 将是“F9A64C2A”。

#include <stdio.h>

int main(int argc,char *argv[])
{
    unsigned char a[] = {42,76,166,249};

    unsigned long long ts;
    ts = a[0] | a[1] << 8U | a[2] << 16U | a[3] << 24U;

    printf("%llX\n",ts);


    return 0;

}

3 个答案:

答案 0 :(得分:5)

在表达式a[3] << 24U中,a[1]的类型为unsigned char。现在,“整数提升”会将其转换为int,因为:

  

以下内容可用于intunsigned int的任何地方   使用:

     

[...]

     

如果int可以表示原始类型的所有值,则该值将转换为   int;   否则,它将转换为unsigned int

(draft) ISO/IEC 9899:1999,6.3.1.1 2)

请注意,移位运算符(除了大多数其他运算符之外)执行“通常的算术转换”,将两个操作数转换为通用类型。但是

  

结果的类型是提升的左操作数的类型。

(6.5.7 3)

在32位平台上,249 << 24 = 4177526784被解释为int,其符号位已设置。

只需更改为

ts = a[0] | a[1] << 8 | a[2] << 16 | (unsigned)a[3] << 24;

修复了问题(常量的后缀U没有影响)。

答案 1 :(得分:1)

 ts = ((unsigned long long)a[0]) | 
    ((unsigned long long)a[1] << 8U) | 
    ((unsigned long long)a[2] << 16U) | 
    ((unsigned long long)a[3] << 24U); 

强制转换可防止将中间结果转换为默认的int类型。

答案 2 :(得分:1)

当自[{1}}自动转换为unsigned char时,某些移位a [i]会产生符号扩展值。

这符合6.3.1算术操作数,6.3.1.1小节标准N1570的布尔,字符和整数,其部分内容为“2.以下内容可用于任何地方可以使用int或unsigned int:... - 具有整数类型的对象或表达式(int或unsigned int除外) 其整数转换等级小于或等于int和unsigned int的等级。 ...如果int可以表示原始类型的所有值...,则该值将转换为int;否则,它将转换为unsigned int。这些被称为整数促销。 ... 3.整数促销保留包括符号的值。“

参见例如www.open-std.org/JTC1/SC22/WG14/www/docs/n1570.pdf

您可以使用以下代码,它可以正常运行:

int