c - 未签名和已签名的扩展

标签 c language-lawyer unsigned

谁能给我解释一下下面的代码输出:

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 中,表达式的结果取决于操作数(或某些操作数)的类型。特别是,1是一个 int (签名),因此 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 的类型将是 unsigned int如果int是 32 位,或 unsigned long否则。

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

相关文章:

c - 基本的,关于说明符

c - 在 C 中,如何创建和发送 shell 变量?

c - Gtk+ 3 笔记本 : how to add pages dynamically?

java - C# 和 Java longs 是否形成交换环?

C 保证重新 : Pointers to Void and Character Types, 类型转换

有符号/无符号值与负值之间的比较

C结构指针

c++ - 为什么不允许使用 `make_unique<T[N]>`?

c# - 是否有用于 C# 的良好、高性能的 unsigned BigInteger 类型?

C++ 如何阻止负数作为参数传递,其中需要无符号