在下面的代码段中,输出不应该是1吗?为什么我输出为-1和4294967295? 我理解的是,变量c,这里是带符号的类型,所以它的值不应该是1?
char c=0xff;
printf("%d %u",c,c);
答案 0 :(得分:1)
c是签名类型。 char是8位。所以你有一个8位有符号数,所有位1.在二进制补码机器上,它的计算结果为-1。
当你做那种事情时,有些编译器会警告你。如果您正在使用gcc / clang,请启用所有警告。
Pedant note:在某些机器上它的值可能是255,如果编译器处理' char'没有签名。
答案 1 :(得分:0)
你得到了正确答案。
%u
格式说明符表示该值为unsigned int
。编译器会自动将您的8位char
提升为32位int
。但是,您必须记住char
是签名类型。所以0xff
的值实际上是-1。
当从char
转换为int
时,该值仍为-1,但它是32位表示,二进制为11111111 11111111 11111111 11111111
或十六进制{{1 }}
如果将其解释为无符号整数,则显然会保留所有位,因为长度相同,但现在将其作为无符号数量处理。
0xffffffff
答案 2 :(得分:0)
C中有三种字符类型,char
,signed char
和unsigned char
。简单char
与signed char
或unsigned char
具有相同的表示形式;选择是实现定义的。您的实施中似乎已签署了简单char
。
所有三种类型都具有相同的大小,可能 8位(CHAR_BIT
,在<limits.h>
中定义,指定一个字节中的位数)。我假设8位。
char c=0xff;
假设普通char
已签名,则值0xff
(255
)超出类型char
的范围。由于您无法将值255
存储在char
对象中,因此会隐式转换该值。此转换的结果是实现定义的,但很可能是-1
。
请谨记这一点:0xff
只是写255
的另一种方式,0xff
和-1
是两个不同的值。您无法将值255
存储在char
对象中;它的值是-1
。整数常量,无论是十进制,十六进制还是八进制,都指定值,而不是表示。
如果您确实需要值为0xff
的单字节对象,请将其定义为unsigned char
,而不是char
。
printf("%d %u",c,c);
当一个比int
更窄的整数类型的值传递给printf
(或任何可变函数)时,如果该类型可以保存该类型的整个范围,它将被提升为int
值,或unsigned int
如果不能。对于char
类型,它几乎可以肯定地提升为int
。所以这个电话相当于:
printf("%d %u", -1, -1);
"%d"
格式的输出很明显。 "%u"
的输出不太明显。 "%u"
告诉printf
相应的参数类型为unsigned int
,但您传递的值为int
。 可能发生的是int
值的表示被视为,就像类型为unsigned int
一样,最有可能产生UINT_MAX
},恰好是您系统上的4294967295
。如果您确实想这样做,则应将值转换为unsigned int
类型。这样:
printf("%d %u", -1, (unsigned int)-1);
定义明确。
你的两行代码正在玩各种类型的游戏,将一种类型的值视为另一种类型,并进行隐式转换,这些转换可能产生实现定义的结果和/或取决于你的编译器碰巧做出的选择。
无论你想做什么,毫无疑问都是一种更简洁的方法(除非你只是试图看看你的实现对这个特定代码的作用)。
答案 3 :(得分:0)
让我们从使用OP的“c,这里是签名类型”
的假设开始char c=0xff; // Implementation defined behavior.
0xff
是一个十六进制常量,其值为255,类型为int
。
...新类型已签名且值无法在其中表示;结果是实现定义的,或者引发实现定义的信号。 §6.3.1.43
因此,c
的值是实现定义的(ID)。让我们假设8位环绕的公共ID行为,因此c
- &gt; -1
签名char
将被提升为int
,因为printf("%d %u",c,c);
的可变参数的一部分与printf("%d %u",-1, -1);
相同。使用-1
打印"%d"
不是问题,并且会打印"-1"
。
使用int -1
打印"%x"
是未定义的行为(UB),因为它是不匹配的说明符/类型,并且不属于在两种类型中都可表示的例外。常见的UB是打印值,就像它在传递之前被转换为unsigned
一样。当UINT_MAX == 4294967295
(4字节)将值打印为-1 + (UINT_MAX + 1)
或“4294967295”时。
因此,使用ID和UB,您会得到一个结果,但强大的代码将被重写,以便两者都不依赖。