当我char
持有一些整数(比方说23),并希望将其转换为更大的整数(int
)时,
我听说可能存在一些问题,因为编译器必须决定是将char
解释为signed
还是unsigned
?
这是真的?这会有问题吗?以及如何避免这种情况?
换句话说(我不确定以下公式是否与上述相同),这种转换可能会出现什么问题:
char someCharVal = //...
int x = someCharVal;
以及如何避免它们?
PS。解释"假人"欢迎
答案 0 :(得分:6)
当将无符号值错误地视为已签名的值时,问题是简单明了的符号扩展。
让我们检查8位和16位二进制补码中5
和-5
的位模式:
8-bit 16-bit
========= ===================
+5 0000 0101 0000 0000 0000 0101
-5 1111 1011 1111 1111 1111 1011
将数字从8位转换为16位时,最高位向左扩展。换句话说,8位数左边的零位将扩展到16位数的上半部分。
类似地,该顶部位中的一位将延伸到左侧。
这就是C扩大它的签名数字的方式(无论如何,对于补码和补码和符号幅度编码是一个不同的问题,但现在很少有实现使用它们。) / p>
因此,如果您要将signed char
转换为signed int
,或unsigned char
转换为unsigned int
,则没有问题。 C会给你正确的价值。
当您切换到signed
类型或从char
类型切换到另一个时,存在问题。
,问题是基础数据的处理方式可能与您的预期不同。
例如,请参阅以下代码,其中包含8位int
和32位#include <stdio.h>
int main (void) {
printf ("unsigned char 50 -> unsigned int %11u\n", (unsigned char)50);
printf ("unsigned char -50 -> unsigned int %11u\n", (unsigned char)-50);
printf ("unsigned char 50 -> signed int %11d\n", (unsigned char)50);
printf ("unsigned char -50 -> signed int %11d\n", (unsigned char)-50);
printf (" signed char 50 -> unsigned int %11u\n", ( signed char)50);
printf (" signed char -50 -> unsigned int %11u\n", ( signed char)-50);
printf (" signed char 50 -> signed int %11d\n", ( signed char)50);
printf (" signed char -50 -> signed int %11d\n", ( signed char)-50);
return 0;
}
类型:
unsigned char 50 -> unsigned int 50
unsigned char -50 -> unsigned int 206 # -50 unsigned is 256-50
unsigned char 50 -> signed int 50
unsigned char -50 -> signed int 206 # same as above
signed char 50 -> unsigned int 50
signed char -50 -> unsigned int 4294967246 # sign extend, treat as unsigned
signed char 50 -> signed int 50 (2^32 - 50)
signed char -50 -> signed int -50
这个输出显示了各种变换,带有我的注释:
signed char -50
第一个不寻常的情况是第二行。它实际上需要unsigned char
位值,将其视为unsigned int
,并将其扩展为signed int
,正确保留其无符号值206.
第二种情况做同样的事情,因为unsigned char
能够保存全部范围的-50
值(在此实现中)。
第三个异常情况会将signed int
扩展为unsigned int
,然后将基础位模式视为char
,为您提供较大的正值。
请注意,当&#34;签名&#34;时,会出现 no 问题。价值不会改变。
C标准并未规定默认情况下char
类型具有的签名,可以是签名或未签名。所以,如果你想要真正的可移植代码,它不应该包含任何&#34;裸体&#34; signed char
种类型。
如果要使用签名值,请使用签名值。这包括使用char
代替unsigned char
明确 。同样,如果要使用无符号值,请在任何地方使用unsigned(包括显式地使用{{1}})。除非你绝对知道将会发生什么,否则不要从签名到无人签名,反之亦然。
答案 1 :(得分:0)
对于signed char
,int
的范围始终等于或大于signed char
的范围,并且从signed char
转换为int
永远是安全的。
对于unsigned char
,理论上UCHAR_MAX
可以等于UINT_MAX
且小于INT_MAX
;从unsigned char
到int
的转换可能不安全。为此,UCHAR_MAX
必须是32767或更大(这在实践中非常罕见);因此转换几乎总是安全的。
由于char
可以是有符号或无符号的,因此从char
到int
的转换几乎总是安全的(理论上并不保证安全)。
然而..
以上所有假设您使用的是(有符号或无符号)char
的全部范围。这是非常罕见的。通常,如果您使用的是char
,则只使用0到127之间的值来避免可移植性问题,如果需要存储负值或更大的正值,则可以使用不同的数据类型(例如{{1} },signed char
,uint8_t
等)。如果int
仅用于存储0到127之间的值,则将char
转换为char
始终是安全的,无论int
和CHAR_MIN
具有哪些值