有人可以向我解释以下代码输出:

void myprint(unsigned long a)
{
    printf("Input is %lx\n", a);
}
int main()
{
    myprint(1 << 31);
    myprint(0x80000000);
}

输出 gcc main.c :
Input is ffffffff80000000
Input is 80000000

为什么 (1 << 31) 被视为有符号而 0x80000000 被视为无符号?

最佳答案

在 C 中,表达式的结果取决于操作数(或某些操作数)的类型。特别是, 1int (有符号),因此 1 << n 也是 int
0x80000000 的类型(包括符号)由规则 here 决定,它取决于系统上 int 和其他未指定的整数类型的大小。选择一种类型,使得 0x80000000(一个很大的正数)在该类型的范围内。

如果您有任何误解:文字 0x80000000 是一个很大的正数。人们有时错误地将其等同于负数,将值与表示混淆。

在您的问题中,您说“为什么 0x80000000 被视为无符号?”。但是,您的代码实际上并不依赖于 0x80000000 的签名。您对它所做的唯一一件事就是将其传递给采用 unsigned long 参数的函数。所以它是签名还是未签名并不重要;当传递给转换时,它被转换为具有相同值的 unsigned long。 (由于 0x80000000unsigned long 的最小保证范围内,因此它不可能超出范围)。

所以,这是 0x80000000 处理。 1 << 31 怎么样?如果您的系统具有 32 位 int(或更窄),则由于有符号算术溢出,这会导致 undefined behaviour。 ( Link to further reading )。如果您的系统有更大的整数,那么这将产生与 0x80000000 行相同的输出。

如果您改用 1u << 31,并且您有 32 位整数,则没有未定义的行为,并且您可以保证看到程序输出 80000000 两次。

由于您的输出不是 80000000,因此我们可以得出结论,您的系统具有 32 位(或更窄)int,并且您的程序实际上会导致未定义的行为。如果 0x80000000 是 32 位,则 unsigned int 的类型将为 int,否则为 unsigned long

关于c - 未签名和已签名扩展,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36981081/

10-13 08:05