我们知道,在C中,整数类型(short
,int
,long
)分为有符号和无符号两种,以int
为例,单纯一个int
代表有符号整型signed int
,这里signed
可以省略;无符号整型需要显示指明unsigned int
。
然而char
是个例外。当然,C语言中,字符类型也分signed char
和unsigned char
,然而单写char
的时候,究竟是有没有符号的?答案是不确定。
C99标准不在手,查了下cppreference-Fundamental types,其中是这么说的:
The signedness of char depends on the compiler and the target platform: the defaults for ARM and PowerPC are typically unsigned, the defaults for x86 and x64 are typically signed.
由实现定义。但这并不表明char
完全等同于signed char
和unsigned char
中的一个。实际上,这三者完全是三个互不相同的类型,可以用一下程序验证:
test_char.c:
#include <stdio.h>
int main()
{
char c;
signed char sc;
unsigned char uc;
(void)(&c == &sc);
(void)(&c == &uc);
(void)(&sc == &uc);
int i;
signed int si;
unsigned int ui;
(void)(&i == &si);
(void)(&i == &ui);
(void)(&si == &ui);
return 0;
}
运行$ gcc -o test_char -std=c99 test_char.c
,我们可以看到编译警告(不相同类型指针间的比较):
test_char.c: 在函数‘main’中:
test_char.c:8:12: 警告:比较不相关的指针时缺少类型转换
(void)(&c == &sc);
^~
test_char.c:9:12: 警告:比较不相关的指针时缺少类型转换
(void)(&c == &uc);
^~
test_char.c:10:13: 警告:比较不相关的指针时缺少类型转换
(void)(&sc == &uc);
^~
test_char.c:16:12: 警告:比较不相关的指针时缺少类型转换
(void)(&i == &ui);
^~
test_char.c:17:13: 警告:比较不相关的指针时缺少类型转换
(void)(&si == &ui);
^~
很明显,int
和signed int
是完全等同的,而char
和signed char
还有unsigned char
之间互不相同。
在实际应用中,这种差别影响很小,因为几乎没有人会使用signed char
,遇到类型转换的时候基本都是char
和unsigned char
之间,如同int
和unsigned int
一样,并不会造成理解上的困扰。
不过有一点,在C99中,有了stdint.h
,定义了一系列类似int32_t
这样的写明位宽的类型。这时候的int8_t
由于是整数类型,因此等同于signed char
,如果某些函数需要一个char *
类型的指针,而实参变量是int8_t *
,此处也要做个转换;而uint8_t
和unsigned char
由于是直接typedef
出来的,就没必要做类型转换了。