int如何转换为char,char如何转换为int?

How int is converted to char and how char is converted to int?

在下面的例子中打印了所有字节的位表示:

#include <stdio.h>
int main (void)
{
  char c = 255;
  char z;
  for (int i = 7; i >= 0; i--) {
    z = 1 << i;
    if ((z & c) == z) printf("1"); else printf("0");
  }
  printf("\n");
  return 0;
}

输出为11111111

现在我们把char c改成int c,这样例子就变成了:

#include <stdio.h>
int main (void)
{
  int c = 255;
  char z;
  for (int i = 7; i >= 0; i--) {
    z = 1 << i;
    if ((z & c) == z) printf("1"); else printf("0");
  }
  printf("\n");
  return 0;
}

现在输出是 01111111.

为什么输出不同?

更新

编译以下内容test.c:

#include <stdio.h>
int main(void)
{
  char c=-1;
  printf("%c",c);
  return 0;
}

$ gcc test.c
$ ./a.out | od -b
0000000 377
0000001

输出结果是377,说明glibc与gcc矛盾,因为signed char会自动转成unsigned char。 为什么会有这样的并发症?默认情况下 char unsigned 是合理的。有什么具体原因不可以吗?

(编辑以澄清 "signed by default")

在第一个清单中,(z == c) 测试了两个 char ;然而,在第二个清单中,(z == c) 测试了一个 char 和一个 int.

为了在 charint 之间执行 &== 操作,编译器将 char 扩展为 int.

的大小

关于第 7 位(第 8 位):

如果您的编译器默认认为 char 是无符号的,条件

(((int)(128) & (int)255) == (int)128)

将呈现 true,并且将打印 1。但是,在您的情况下,结果为假,并显示 0

原因可能是您的编译器认为 char 已签名(默认情况下类似于 gcc)。在这种情况下,设置为 1 << 7char 实际上是 -128,而在 int 中(至少两个字节) 255 为正。

(char)-128 扩展为 int 是 (int)-128,因此条件

if ((z & c) == z) 

阅读

if (((int)(-128) & (int)255) == (int)-128)

在这种情况下这是错误的。

对于 char 到 int,您必须将 char 定义为 unsigned,因为默认情况下 char 或任何类型都被视为 singed。

 int main (void)
 {
 int c = 255;
 unsigned char z;
 int i;
 for (i = 7; i >= 0; i--) {
 z = 1 << i;
 if ((z & c) == z) printf("1"); else printf("0");
 }
 printf("\n");
 return 0;
 }
  • 这里第一个问题是char类型。这种类型不应该用于存储整数值,因为它具有实现定义的符号。这意味着它可以是有符号的也可以是无符号的,你会在不同的编译器上得到不同的结果。如果 char 在给定的编译器上未签名,则此代码将按您预期的方式运行。

    但如果 char 已签名,char c = 255; 将导致值过大。值 255 然后将以某种特定于编译器的方式转换为带符号的数字。通常通过将原始数据值转换为等效的二进制补码。

    GCC 等优秀的编译器会对此发出警告:"overflow in implicit constant conversion"。

    通过从不使用 char 存储整数来解决此错误。请改用 uint8_t

  • 当您尝试将 1 << 7 存储在给定编译器上签名的 char 类型中时,会出现同样的问题。当发生这种情况时,z 将最终为负值 (-128)。

  • 在表达式 z & c 中,两个操作数都是静默提升为类型 int 的整数。每当您使用 小整数类型 例如 char 时,大多数 C 表达式都会发生这种情况。

    & 运算符不关心操作数是否有符号,它将对变量的 "raw data" 值进行按位与运算。当 c 是一个带符号的 char 并且具有原始值 0xFF 时,您将得到一个负数的结果,并设置了符号位。在二进制补码计算机上的值 -1

所以回答为什么在这两种情况下得到不同的结果:

当您将类型切换为 int 时,值 255 将适合 c 而不会转换为负值。 & 操作的结果也将是一个 int 并且这个 int 的符号位永远不会被设置,这与 char 的情况不同。

当您执行 -128 & 255 时,结果将是 128 (0x80)。这是一个正整数。然而,z 是一个负整数,值为 -128。它会被 == 运算符提升为 int 但符号会保留。由于 128 不等于 -128,因此 MSB 将打印为零。

如果将 char 切换为 uint8_t,您会得到相同的结果。