1010
我非常确定大多数字符串函数的存在都早于unsigned char。
char类型可以是有符号或无符号的。C和C++标准明确允许两种类型(它始终是一个独立的类型,不同于unsigned char或signed char,但具有与其中一种相同的取值范围)。
虽然C语言的字符串函数使用char *类型, 但在大部分C++中使用的是 std::string。
- Jerry Coffin2当然,在指向有符号/无符号字符的指针之间,内存没有任何区别。 - Martin Beckett字符串函数的出现早于语言中添加“unsigned”的功能,而PDP-11硬件使得将字符视为有符号更加高效,那时候是7位ASCII的时代。 - Jim Balter回答链接1010C标准对于普通的char是有符号还是无符号并没有表态,而且将char与signed char区分对待。此外,基本ASCII字符集包括大多数主要控制字符和英文可打印字符,由128个字符组成,因此可以用带符号的char充分表示(至少在每字节提供8位的任何系统上都是如此)。正如Jim Balter指出的(请参见下面的评论), ASCII不构成C语言的完整基字符集,但我认为它包括了常用的大多数字符。此外,还有大量的C代码依赖于ASCII的特性(尽管不一定是独特的)(例如,特殊字符NUL具有零值,字母数字字符按顺序递增排列等)。
- Greg E.152我没有看到你在问题中指出了错误的前提。这个问题实际上是非常合理的,答案与历史有关。如果PDP-11有处理字节作为无符号值的指令,那么字符就会是无符号的,并且处理字符的代码将会少得多(例如,每次调用ctype.h的...或to...函数都会传递一个字符)。 - Jim Balter@JimBalter,OP特别提到了ASCII字符集与char的有符号性之间的关系,我试图解决这个问题,而且我没有在任何C标准中就ASCII发表任何声明。我有冒犯你吗?还是我的想象?我重申,由于你显然对这个主题有很多话要说,请向OP提供完整的回复,而不是用评论淹没我。这对每个人都更有用。 - Greg E.当前问题中没有提到ASCII,而且问题暗示了使用超过7位的字符。你的回答给人的印象是7位ASCII是C语言的基本字符集,这是不正确的。 - Jim Balter@JimBalter,在原始问题中提到了ASCII,如果你想把我的回答解释为对C基本字符集做出全局性陈述,那么你需要读很多内容。此外,我认为我关于ASCII的声明增加了价值,仍然与当前措辞的问题相关,并且据我所知,是完全准确的。 - Greg E.1@JimBalter,你说得对,鉴于OP问题的变化,我会尝试为我的ASCII陈述添加一些背景。谢谢,并为我的争论口气道歉。 - Greg E.显示剩余10条评论回答链接55Jim Balter在评论中指出:
PDP-11关于字节的指令将它们视为有符号量,因此早期的C编译器也是这样处理的,并且无符号量甚至不存在。
我强烈怀疑这就是为什么默认字符类型char不需要是无符号的答案,但为了确保需要一份书面历史记录的引用。
至于为什么它也不需要是有符号的(!),在非二进制补码机器上(例如我所知道的唯一可能仍在使用的Clearpath Dorado),signed char不能容纳所有unsigned char的值,因为它会浪费一个比特模式在负零上,或者其他该比特模式被利用为何种作用。如果char被要求是有符号的,则这将成为重新解释通用数据作为char值序列的问题。因此,在这样的计算机上,char必须是无符号的,否则软件将不得不进行极端的扭曲来处理它。
- Cheers and hth. - Alf61仅免责声明:距离我上次接触PDP-11汇编已经有大约30年了,我无法真正回忆起它如何处理字节,或者它是否提供例如单字节乘法和除法,即它是否将字节视为有符号量。因此,我的怀疑完全基于@Jim Balter知道他在谈论什么,并且这听起来并不牵强。我不再知道自己的记忆中的PDP-11内容(我记得的几乎都是PDP-11汇编涉及@符号,寄存器编号和内存映射)。 - Cheers and hth. - Alf@Alf,促销规则确保所有计算都是在int上进行的,而不是在short或char上进行的。因此,唯一的问题是将char扩展为int时是更容易进行符号扩展还是零扩展。(关于允许char无符号的需求,即使只有C++明确要求基本集中的字符为非负数,我非常确定它与C的实践相对应,并且允许EBCDIC的实现具有无符号的char)。 - AProgrammer@AProgrammer:汇编语言中没有升级规则。当我们谈论汇编语言,或者更确切地说,机器码指令时,我们谈论的是编译器代码生成的方便性,特别是在C语言形成的早期和中期(即20世纪70年代),而第一个C标准是在1989年出现的。对于char值的非负假设存在于许多标准库函数中,例如isupper(这会使新手犯错)。 - Cheers and hth. - Alf1@Cheersandhth.-Alf: 我喜欢你的帖子中所呈现的历史视角。有时候,如果人们指出某些事情之所以以特定方式工作是源于历史而非逻辑,计算机科学课程就会变得更加宽敞。 - Alexander Oh@Cheersandhth.-Alf:在寄存器大于字节的处理器上,有些处理器具有“使用零填充将字节加载到字寄存器”的指令,有些处理器具有“使用符号扩展将字节加载到字寄存器”的指令,有些处理器具有“将字节加载到字寄存器的一部分,其余部分不受影响”的指令,还有一些处理器具有两种或更多的指令。对于只有前两种形式之一的处理器,我会将该形式视为针对这些处理器的汇编语言的“提升规则”。 - supercat@Alex:许多人似乎对标准的各个方面赋予了奇怪的崇高地位。标准允许实现的许多灵活性,旨在避免强制现有的非常规实现以可能使它们对它们已经服务的目的不再有用(因此显然是合适的方式)进行更改,并且不是为了邀请编译器在生成普通平台代码时变得具有创造力。 - supercat回答链接22其他人已经探讨了C语言最初和(后来)标准化时为什么会这样,但这种看似反常的现象之所以持续到今天,还有另一个原因。
那就是当你使用char表示字符时,你不需要知道它是有符号还是无符号。标准库提供了可移植的函数来操作字符,而不管它们的表示方式如何。如果你忽略这些函数,坚持在字符上进行比较和算术运算,那么你就应该承担由此引入的每一个bug。
举个简单的例子,通常会用表达式c >= ' '或等价的c >= 0x20来检查一个字符是否可打印,但你应该使用isprint(c)。这样,你就不会暴露自己于有符号/无符号混淆之中,并可能在程序中引入平台相关的错误。
一旦你养成了只将signed char和unsigned char作为小型(通常为8位)整数进行算术运算的习惯,而在处理字符数据时只使用char,那么char是一个具有实现定义的符号类型就会变得非常自然,字符串处理函数总是使用char和char *而不是有符号或无符号的变体也会更加自然。对于char的符号性来说,它似乎与bool的符号性一样相关性不大。
- Dan Hulme11-1 上述内容是不正确的。C标准要求分类函数的参数必须是非负数,否则为EOF。因此,为了正确使用这些函数,实际参数必须转换为“unsigned char”。否则,对于非ASCII字符,您将面临正式的未定义行为。例如,Visual C++调试运行时库会捕获某些函数的此类问题,并(即使程序在没有此问题的情况下也能正常工作!)导致程序崩溃... - Cheers and hth. - Alf回答链接22正如Bjarne在《C++程序设计语言》中所说,char类型是有符号还是无符号取决于具体实现,而C++提供了两种类型以适应不同的实现。
- xvatar回答链接00标准中的Char既不是有符号的也不是无符号的。请参见https://dev59.com/yXI95IYBdhLWcg3w_zas#2054941
- vines59更正:char 可以是有符号的也可以是无符号的(但它与 signed char 和 unsigned char 是不同的类型)。 - Keith Thompson@keith,在C++中有点复杂(不确定在C中是否相同)。在C++中,char可以是有符号的或无符号的,并且是整数类型。但它既不是有符号整数类型也不是无符号整数类型。因此,您需要非常小心地措辞具体的语句。 - Johannes Schaub - litb@JohannesSchaub-litb 为什么 char 可以是有符号或无符号的整数类型,但它既不是有符号整数类型也不是无符号整数类型?最后一部分与第一部分矛盾了吗? - Alexey Frunze@alex 不,它并不违背第一部分。没有有符号类型的正式定义,所以人们和标准本身都认为它意味着“可以表示负值的类型”。但是有一个有符号整型的定义,其中明确列出了所有类型。char以及bool都不包含在该列表中。您会发现numeric_limits
在C++中,使用std::string。而在C中,当引入无符号类型时,使用模式已经太过固定,我不排除会有效率上的考虑。
“没有有意义的字符值低于零。”
好吧,在C++标准中有一个约束条件,即基本字符集中的字符为正数。但是认为该约束条件适用于所有字符是天真的。
该约束条件强制允许EBCDIC作为编码系统的实现将其char设为unsigned。
大多数现代编译器(如GCC、MSVC)默认将char视为signed。
gcc的行为取决于目标平台,并具有更改目标默认值的选项。
- AProgrammer5"标准中并没有规定基本字符集中的字符必须为正数,除了包含最小字符集和整数连续外,唯一的限制是它们需要适合一个字节。" -- 不,没有这样的限制。除了包括最小字符集和整数连续之外,唯一的限制是它们适合一个字节。 - Jim Balter@JimBalter,参见C++1998,2.2/3,C++2011 2.3/3(它使用非负数,显然\0具有零值),但我在我的档案中注意到我没有在C标准中找到相应的约束条件(这个注释是在C11之前的日期,所以我没有在那里搜索,但我可能看过C90和C99;在C11中,它不在2.3/3的直接等价物5.2.1/3中)。我已经添加了一个限定。 - AProgrammer抱歉,我忘记了这个标签既标记了C又标记了C++,而你也在讨论C++和C。感谢您的澄清。C标准确实指出ctype函数的参数必须表示为无符号字符(或EOF),实际上可以理解为字符集是正数。 - Jim Balter@JimBalter,我不这么认为。ctype函数的参数是一个int类型,它可以是EOF或char强制转换为unsigned char(顺便说一下,这正是getc返回的内容)。我在使用带有有符号char的Latin1语言环境的实现时使用了它们,因此包括负字符。 - AProgrammer我认为这是一个语义上的争议。当用有符号的char或char作为有符号实现时,带有第8位设置的字符在存储时具有负值,但这并不意味着字符集包含负值; API(getc和ctype)暗示了相反的情况。我认为C++的约束澄清了这一点。 - Jim Balter回答链接