将char安全地转换为整数

时间:2014-04-07 06:36:18

标签: c

当我char持有一些整数(比方说23),并希望将其转换为更大的整数(int)时, 我听说可能存在一些问题,因为编译器必须决定是将char解释为signed还是unsigned? 这是真的?这会有问题吗?以及如何避免这种情况?

换句话说(我不确定以下公式是否与上述相同),这种转换可能会出现什么问题:

   char someCharVal = //...
    int x = someCharVal;

以及如何避免它们?

PS。解释"假人"欢迎

2 个答案:

答案 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 charint的范围始终等于或大于signed char的范围,并且从signed char转换为int永远是安全的。

对于unsigned char,理论上UCHAR_MAX可以等于UINT_MAX且小于INT_MAX;从unsigned charint的转换可能不安全。为此,UCHAR_MAX必须是32767或更大(这在实践中非常罕见);因此转换几乎总是安全的。

由于char可以是有符号或无符号的,因此从charint的转换几乎总是安全的(理论上并不保证安全)。

然而..

以上所有假设您使用的是(有符号或无符号)char的全部范围。这是非常罕见的。通常,如果您使用的是char,则只使用0到127之间的值来避免可移植性问题,如果需要存储负值或更大的正值,则可以使用不同的数据类型(例如{{1} },signed charuint8_t等)。如果int仅用于存储0到127之间的值,则将char转换为char始终是安全的,无论intCHAR_MIN具有哪些值