C语言中的无符号数值

31

我有以下代码:

#include <stdio.h>

int main() {
    unsigned int a = -1;
    int b = -1;
    printf("%x\n", a);
    printf("%x\n", b);

    printf("%d\n", a);
    printf("%d\n", b);

    printf("%u\n", a);
    printf("%u\n", b);
    return 0;
}

输出结果为:

ffffffff
ffffffff
-1
-1
4294967295
4294967295

我可以看出一个值根据传递给 printf 函数的值被解释为有符号或无符号。 在两种情况下,字节是相同的 (ffffffff)。那么,“unsigned”一词的含义是什么?


是的,但这是由printf函数完成的,我无法理解unsigned单词所起的作用。在我的示例中,对于有符号和无符号变量,我都可以看到它的值是有符号或无符号的。为了澄清,如果我可以看到一个有符号变量打印为有符号或无符号,那么unsigned单词是用来做什么的? - rvillablanca
5
无法用 %d 打印无符号值或用 %u%x 打印有符号值,这是未定义行为。因此,您无法看到已签名的变量作为有符号或无符号打印出来。 - The Paramagnetic Croissant
3
你的printf语句中有一些是未定义行为(UB),这是本问题的主要原因。 - David Heffernan
2
这是未定义行为。没有人能理解你所说的“打印ffffffff可以作为有符号-1或无符号4294967295打印”。如果您首先将值转换为正确的类型并在printf中使用相应的格式,则可以将相同的位模式视为有符号或无符号。 - phuclv
2
可能是重复的问题:当我将负值分配给无符号整数时会发生什么? - Bo Persson
显示剩余4条评论
3个回答

31

int -1赋值给一个 unsigned: 因为-1不在范围[0...UINT_MAX]内,所以倍数UINT_MAX + 1被添加直到答案在范围内。 显然,在OP的计算机上,UINT_MAXpow(2,32)-1或429496725,因此a的值为4294967295

unsigned int a = -1;

"%x""%u" 指示符需要匹配的 unsigned 类型。由于它们不匹配,所以“如果转换规范无效,则行为未定义。如果任何参数类型与相应的转换规范不匹配,则行为未定义。”C11 §7.21.6.1 9。printf 指示符不会更改 b

printf("%x\n", b);  // UB
printf("%u\n", b);  // UB

"%d" 指定符需要匹配的是一个 int。由于两者不匹配,因此会出现更多的 UB

printf("%d\n", a);  // UB

考虑到未定义行为,结论不被支持。


两种情况下,字节都相同(ffffffff)。

即使具有相同的位模式,不同类型可能具有不同的值。作为无符号类型的ffffffff具有4294967295的值。作为int,根据带符号整数编码,它的值为-1,-2147483647或TBD。作为float,它可能是NAN

什么是无符号字?

unsigned存储在范围[0 ... UINT_MAX]内的整数。 它永远不会有负值。 如果代码需要非负数,请使用unsigned。 如果代码需要可为正,负或零的计数数字,请使用int


更新:为避免编译器警告将已签名的int赋值给unsigned,请使用以下内容。这是一个unsigned 1u被否定 - 如上所述,这是明确定义的。 效果与-1相同,但向编译器传达了直接意图。

unsigned int a = -1u;

你关于UB的说法是不正确的。请重新阅读你引用的段落之前的内容。简而言之,遵循语法的任何转换说明符都是“有效”的。换句话说,在printf(“%d”,“foo”)中,说明符“%d”是有效的,就像引用的段落所指的那样。当然,尝试将字符串打印为整数是UB,但不是因为你认为的原因。相反,“如果允许”,将执行适当的类型提升或转换,由于从字符串到整数不允许进行类型提升或转换,因此它变成了UB。 - AnorZaken
@AnorZaken 回答已经修改,强调printf的格式说明符和参数类型不匹配。 - chux - Reinstate Monica
为什么无符号整数'b'的说明符%u未定义? - Columbo
@Columbo 在 int b = -1; 中,b 不是一个无符号整数,而是一个值为-1的 int。使用不匹配的格式说明符进行打印是未定义行为 - 对于正数有一个例外,但这里不适用。 - chux - Reinstate Monica
这样写很容易让人误解,因为你只引用了 a 的定义,然后又使用了 b。请在你的回答中引用两个变量的定义。 - Columbo

0

在变量声明中使用unsigned对程序员本身更有用-不要将变量视为负数。正如您所注意到的,对于4字节整数,-14294967295具有完全相同的位表示。这完全取决于您想要如何处理查看它们。

语句unsigned int a = -1;-1转换为二进制补码,并将其位表示分配给aprintf()说明符xdu显示了存储在变量a中的位表示在不同格式下的样子。


0

当你将unsigned int a to -1;初始化时,这意味着你正在将-12's补码存储到a的内存中。
也就是说,它等同于0xffffffff4294967295

因此,当你使用%x或%u格式说明符打印它时,你会得到那个输出。

通过指定变量的有符号性来决定可以存储的值的最小和最大限制。

例如,对于unsigned int:范围从0到4,294,967,295,而int:范围从-2,147,483,648到2,147,483,647

有关有符号性的更多信息,请参见this


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接