在C语言中,使用char(plain char)或signed/unsigned char存储字符是否有区别?

3

我有一个问题,我在SO上读了一些帖子,询问如何使用charsigned charunsigned char;在那篇文章中,他们回答说,为了存储字符,我们必须使用char,而对于使用小数据,使用signed/unsigned char,但是,据我所知,char是实现定义的,因此它可以等于signed charunsigned char

问题是,我可以使用charsigned charunsigned char来存储字符吗? 如果答案是“不行”,我的下一个问题是,为什么?你能解释一下为什么要严格使用char(普通字符)来存储字符吗?

提前感谢!


1
如果您正在使用纯文本,则可能希望使用普通的char,因为大多数C的字符串相关函数都是定义为使用charchar *。如果您正在使用原始字节,特别是如果您正在进行一些数学运算以将相邻的字节组合成多字节整数,则通常非常有用将所有内容声明为unsigned charunsigned char *,因为您可以避免许多与符号扩展有关的烦人问题。 - Steve Summit
在编程中,使用 char 表示字符和字符串。使用 unsigned char 表示低级别的原始数据。特别是在使用位运算符时,应该使用 unsigned char。在需要对小型数据类型进行有符号计算的(很少见的)情况下,使用 signed char - Support Ukraine
下面有一些很好的答案。请确保您接受最佳答案,或在您认为不够完善的答案下进行评论。 - Allan Wind
3个回答

2

char保证总是足够大,可以存储称为基本字符集的内容,即英语中使用的基本拉丁字母和符号。例如7位ASCII码。只要您仅用于存储文本,就不必担心它的大小和符号。

当您将char用于存储原始数据或在算术运算中使用时,问题才会出现。在这种情况下,符号可能很重要。由于我们无法以可移植的方式知道char的符号,因此它不适用于这些目的。默认情况下,char是带符号还是无符号的?

处理原始数据字节时最好使用unsigned char/uint8_t类型。同样,在8位类型上进行无符号算术运算时也应使用这个类型。

signed char/int8_t基本上只用于在资源非常有限的系统(如8位CPU)上进行带符号算术运算。

unsigned char没有被普遍使用的原因是历史原因。C语言实际上将charunsigned charsigned char视为三种不同的类型。例如,unsigned char x; char*y = &x;是无效的,我们必须进行显式转换才能使其工作。然而,在二进制级别上,所有字符类型都与彼此别名。因此,如果我们将一个unsigned char数组传递给例如strcpy,它将正常工作,但我们需要将参数强制转换为char*,这有点繁琐。最好将所有文本保留在char类型中,避免这样的转换。

(理论上,字符类型可以大于8位,那么int8_t/uint8_t类型就不存在了。但这种奇特的情况只在编写某些DSP系统的C语言时才相关。)


1
使用C语言存储字符时,使用普通的char还是signed/unsigned char有区别吗?
是的,当字符对象为有符号字符且为负值时与无符号字符相同的位模式为正值时,使用>>,*,/,%会产生差异。
将负字符分配给int可能会出现意外的符号扩展。
is...()在字符参数为负数(非EOF)时会调用未定义行为(UB)。
_Generic中的情况区分char、signed char和unsigned char。
严格:使用旧式的非2'S补码并使用带符号字符时,用户代码经常无法正确区分空字符的+0和-0。
转换为其他类型时,有符号类型比无符号类型具有更多的实现定义行为,因此降低了可移植性。

"signed char在处理UTF-8编码文本方面存在劣势

...还有其他问题。

...并非总是如此

str...()的行为就好像字符是unsigned char,而不管charsigned还是unsigned。这对于某些函数很重要,例如strcmp(),因为一个字符串中的差异涉及到负的char的情况。

"%c","%s"*scanf(),*printf() 中匹配所有3种类型(或指向它们的指针)。

三个字符类型没有填充位,并且占用相同的空间,尽管即将被取消的非2的补码编码允许有一个陷阱表示为signed字符类型。


“我可以使用char、signed char或unsigned char来存储字符吗?”
可以。
对于字符串操作,char在匹配str..()函数签名方面具有优势。
对于逻辑和原始字节码,请使用unsigned char。
当需要小的有符号值时,请使用signed char。
@Steve Summit, @Support Ukraine
如果答案是“不行”,我的下一个问题将是:为什么?你能解释一下使用严格字符(普通字符)存储字符的原因吗?

0

正如你所说,如果 char 是有符号或无符号是实现定义。

如果您需要特定版本,请指定它。 ASCII 是7位,因此对于它并不重要。 如果您需要8位或更多(例如UTF-8),则取决于您如何使用数据。 例如,左移对于无符号值是很好定义的,但如果左操作数为负,则实现定义。 对于无符号来说,if(ch<0)是无操作的,但对于有符号来说可能非常重要。

在即将发布的C 2023标准中,新类型 char8_t 可能会引起您的兴趣。 它是无符号的,并且与 unsigned char 相同。


有关 char8_t 的任何参考资料吗? - chux - Reinstate Monica
嗯,我确实找到了 https://stackoverflow.com/a/66973420/2410359 - chux - Reinstate Monica
1
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3054.pdf 是2022年9月3日的草案。 - Allan Wind

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接