C语言 “int”和“unsigned int”之间的真实的差异

pieyvz9o  于 2022-12-02  发布在  其他
关注(0)|答案(9)|浏览(318)

整数

32位int数据类型可以保存-2,147,483,648到2,147,483,647范围内的整数值。您也可以将此数据类型称为signed int或signed。

无符号整型

32比特不带负数号的int资料类型可以储存0到4,294,967,295范围内的整数值。您也可以将此资料类型简称为不带负数号。
好吧,但是,在实践中:

int x = 0xFFFFFFFF;
unsigned int y = 0xFFFFFFFF;
printf("%d, %d, %u, %u", x, y, x, y);
// -1, -1, 4294967295, 4294967295

没什么区别,我有点糊涂了

tpxzln5u

tpxzln5u1#

这里有一个隐式强制转换,因为你告诉printf应该使用什么类型。
试试这件:

unsigned int x = 0xFFFFFFFF;
int y = 0xFFFFFFFF;

if (x < 0)
    printf("one\n");
else
    printf("two\n");
if (y < 0)
    printf("three\n");
else
    printf("four\n");
kxxlusnw

kxxlusnw2#

是的,因为在您的情况下,它们使用the same representation
位模式0xFFFFFFFF在解释为32 b有符号整数时看起来像-1,在解释为32 b无符号整数时看起来像4294967295。
它和char c = 65一样,如果你把它解释成一个有符号整数,它就是65,如果你把它解释成一个字符,它就是a
正如R和pmg所指出的,从技术上讲,传递与格式说明符不匹配的参数是未定义的行为,所以程序可以做任何事情(从打印随机值到崩溃,再到打印“正确”的东西,等等)。
标准以7.19.6.1-9指出
如果转换规范无效,则行为不完整。如果任何参数不是相应转换规范的正确类型,则行为不完整。

ndasle7k

ndasle7k3#

这两种运算在内存和寄存器中的存储方式没有区别,没有带符号和不带符号版本的int寄存器,也没有带符号的信息与int一起存储,只有在执行数学运算时才会有区别,CPU中内置了带符号和不带符号版本的数学运算,带符号性告诉编译器使用哪个版本。

gijlo24d

gijlo24d4#

问题在于您调用了Undefined Behaviour
当您调用UB时,任何事情都可能发生。
作业还可以;在第一行中有一个隐式转换

int x = 0xFFFFFFFF;
unsigned int y = 0xFFFFFFFF;

但是,对printf的调用是不正确的

printf("%d, %d, %u, %u", x, y, x, y);

%说明符与参数类型不匹配是UB
在您的情况下,您可以提供1 int、1 unsigned int、1 int和1 unsigned int,以此顺序指定2 int和2 unsigned int
别做傻事!

pjngdqdw

pjngdqdw5#

intunsigned int的内部表示是相同的。
因此,当您将相同的格式字符串传递给printf时,它将被打印为相同的格式。
但是,当您比较它们时,会发现它们之间存在差异。请考虑:

int x = 0x7FFFFFFF;
int y = 0xFFFFFFFF;
x < y // false
x > y // true
(unsigned int) x < (unsigned int y) // true
(unsigned int) x > (unsigned int y) // false

这也是一个警告,因为在比较有符号整数和无符号整数时,其中一个将被隐式转换以匹配类型。

edqdpe6u

edqdpe6u6#

二进制表示是密钥。示例:十六进制无符号整数

0XFFFFFFF = translates to = 1111 1111 1111 1111 1111 1111 1111 1111

它表示4,294,967,295的十进制正数。但我们也需要一种表示负数的方法。所以大脑决定用二进制补码。简而言之,他们取最左边的位,并决定当它是1(后面至少还有一个其他位设置为1)时,数字将是负数。而最左边的位设置为0时,数字将是正数。现在让我们看看会发生什么

0000 0000 0000 0000 0000 0000 0000 0011 = 3

再加上我们最终达到的数字。

0111 1111 1111 1111 1111 1111 1111 1111 = 2,147,483,645

带符号整数的最大正数。让我们再加1位(二进制加法会向左溢出,在本例中,所有位都设置为1,因此我们停留在最左边的位)

1111 1111 1111 1111 1111 1111 1111 1111 = -1

所以我想简而言之,我们可以说,一个允许负数,而另一个不允许,因为**符号位,**或者最左边的位,或者最高有效位。

zpjtge22

zpjtge227#

他问的是 * 真实的 * 的区别。当你谈论未定义的行为时,你是在语言规范提供的保证水平上--它与现实相差甚远。要了解真正的区别,请查看以下片段(当然这是UB,但它在你最喜欢的编译器上定义得很完美):

#include <stdio.h>

int main()
{
    int i1 = ~0;
    int i2 = i1 >> 1;
    unsigned u1 = ~0;
    unsigned u2 = u1 >> 1;
    printf("int         : %X -> %X\n", i1, i2);
    printf("unsigned int: %X -> %X\n", u1, u2);
}
ryevplcw

ryevplcw8#

类型只是告诉你位模式应该代表什么。位只是你对它们的理解。相同的序列可以用不同的方式解释。

wvt8vs2t

wvt8vs2t9#

printf函数 * 解释 * 您根据匹配位置的格式说明符传递给它的值。如果您告诉printf您传递的是int,但传递的是unsignedprintf会将其中一个重新解释为另一个,并打印您看到的结果。

相关问题