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

标签 c type-conversion implicit-conversion

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

#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 是合理的。有什么具体原因吗?

最佳答案

  • 这里的第一个问题是 char类型。这种类型不应该用于存储整数值,因为它具有实现定义的符号。这意味着它可以是有符号的也可以是无符号的,你会在不同的编译器上得到不同的结果。如果char在给定的编译器上未签名,那么此代码将按您预期的方式运行。

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

    GCC 等优秀的编译器会对此发出警告:“隐式常量转换溢出”。

    通过从不使用 char 来解决此错误用于存储整数。使用 uint8_t反而。

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

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

    &运算符不关心操作数是否有符号,它会对变量的“原始数据”值进行按位与运算。当c是签名char并具有原始值 0xFF ,你会得到一个负的结果,并设置了符号位。值 -1在二进制补码计算机上。

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

当您将类型切换为 int 时, 值 255将适合内部 c而不会转换为负值。 & 的结果操作也将是一个 int和这个 int 的符号位永远不会被设置,不像在 char 中那样案例。

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

如果切换 char,您会得到相同的结果至 uint8_t .

关于c - int如何转换为char,char如何转换为int?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40479358/

相关文章:

C - 空指针和偏移量

c - 为什么 func 看起来和 C 中的 &func 一样?

c++ - 编译器如何隐式地进行这种转换?

c - 为什么我的阵列打印的数字与分配过程中打印的数字不同?

管脚映射代码

Collat​​z 猜想代码 "bouncing"介于 13 和 19 之间

database - 使用 `BEFORE INSERT` 触发器更改传入数据的数据类型以匹配 PostgreSQL 中的列数据类型

c++ - 初始化nullptr_t时,0与其他整数如何区分?

c++ - 类型转换问题

c++ - 使用隐式转换从字符串流插入