非二进制补码平台上的char中的ASCII码表示形式

时间:2019-11-03 12:16:47

标签: c casting ascii

在主流平台上都很容易:字母'A'具有ASCII码65,所以它是(char)65,也是(unsigned char)65,也是(signed char)65内存中的位顺序相同。

但是据我所知,C标准不要求使用任何特定方案对带符号的数字进行编码。因此,在某些机器上(signed char)65(unsigned char)65可能通过不同的位序列表示。 (例如:https://en.wikipedia.org/wiki/Offset_binary)我是对的还是该行为在标准中的某个地方被禁止?

如果可能的话:其中哪一个将是“ A”(例如在某些通用文本文件编辑器中)?它与纯char类型的签名有某种联系吗?

是否有一种可移植的方式来处理此类案件?

同一问题的另一面。

示例我有char some_text[100];,我想将其读取为未签名的代码。有两种选择:

(unsigned char)(some_text[i]) =会将有符号值转换为无符号值,并尽可能保留其数字值

*(unsigned char*)(some_text+i) =将保留位序列,但值可能会因平台而异

在思考上述此类异国情调的平台时,哪个会更便携,更正确?

2 个答案:

答案 0 :(得分:2)

ASCII码是0到127之间的数字。

C标准要求,对于带符号和无符号字符类型,这些数字的表示必须相同。

  

存储在无符号位域和unsigned char类型的对象中的值应使用纯二进制表示法表示

  

signed char不得有任何填充位。恰好有一个符号位。作为值位的每一位应具有与相应无符号类型的对象表示形式中的同一位相同的值

这些规定允许人们在有符号和无符号char类型之间(并且更重要的是)在其数组之间安全地进行转换。这些转换的行为可预测且可移植。当通过signed char左值访问unsigned char类型的对象,并且原始对象的值是非负数(所有ASCII码均为)时,保证访问的值与原始值。相反,如果通过unsigned char左值访问signed char,并且原始值在有符号范围内(所有ASCII码都适用),则可以保证其不变。这很重要,因为各种API经常使用签名不方便的字符数组;我们希望确保可以将此类API与首选字符类型进行简单转换。

负值呢?这些不是ASCII,但我们经常使用其他字符集和编码(例如UTF-8),并且这些字符可能包含负数成员。

负值可以用三种方法之一准确表示。

  

如果符号位为1,则应通过以下方式之一修改值:

     

取反符号位0的对应值(符号和大小);
  符号位的值为-(2M)(二进制补码);
  符号位的值为-(2M-1)(补码)。

在这里,我们有一个符号和幅度表示为负零的问题。它无法通过无符号类型往返。因此,此类实现无法轻易支持某些字符编码(如UTF-8)。不过,对于ASCII来说这不是问题。

对于其他整数类型,此处的表示并不十分重要。当您使用例如int代表ASCII值,通常您对值感兴趣,而不是对表示感兴趣。您可以在C支持的所有整数类型之间安全地转换0到127的值(其他整数类型可能具有填充位,但除此之外,上述大多数情况也是如此;这无关紧要,因为普通编程几乎不会受到影响)。 / p>

使用不同的char表示形式的奇异平台无法支持标准C,因此为此类平台进行可移植性的写作没有意义。

最后,如果将ASCII替换为平台实际使用的任何基本字符集,则同样如此,只是范围可能不同。

答案 1 :(得分:1)

首先,char本身具有实现定义的签名,因此取决于编译器,它可以是签名的也可以是未签名的。

任何强制转换为有符号或无符号的7位字符符号代码的值将始终为正值。说到ASCII,我们只指原始的7位表。它永远不会有负值。因此,底层的符号表示形式无关紧要,因为符号值只要不大于7位,就永远不能为负。

总结您的问题:

  

因此,在某些机器上,(带符号的字符)65和(无符号的字符)65可能通过不同的位序列表示。

否。

  

我是对的还是该行为在标准中的某个地方被禁止?

是,C17 6.3.1.3。 “将整数类型的值转换为_Bool以外的其他整数类型时,如果该值可以用新类型表示,则该值不变。”

唯一会遇到可移植性问题的代码是依赖于8位或更多位符号表的代码。但是通常会使用wchar_t