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.
为了在 char 和 int 之间执行 &
和 ==
操作,编译器将 char 扩展为 int.
的大小
关于第 7 位(第 8 位):
如果您的编译器默认认为 char 是无符号的,条件
(((int)(128) & (int)255) == (int)128)
将呈现 true,并且将打印 1
。但是,在您的情况下,结果为假,并显示 0
。
原因可能是您的编译器认为 char 已签名(默认情况下类似于 gcc)。在这种情况下,设置为 1 << 7
的 char 实际上是 -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
,您会得到相同的结果。
在下面的例子中打印了所有字节的位表示:
#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.
为了在 char 和 int 之间执行 &
和 ==
操作,编译器将 char 扩展为 int.
关于第 7 位(第 8 位):
如果您的编译器默认认为 char 是无符号的,条件
(((int)(128) & (int)255) == (int)128)
将呈现 true,并且将打印 1
。但是,在您的情况下,结果为假,并显示 0
。
原因可能是您的编译器认为 char 已签名(默认情况下类似于 gcc)。在这种情况下,设置为 1 << 7
的 char 实际上是 -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
,您会得到相同的结果。