首页 > 解决方案 > 非二进制补码平台上 char 中的 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)= 将保持位序列,但值可能会因平台而异

在考虑上述这些奇异平台时,哪一个更便携和正确?

标签: ccastingascii

解决方案


ASCII 码是数字 0 到 127。

C 标准要求这些数字的表示对于有符号和无符号字符类型是相同的。

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

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

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

负值怎么办?这些不是 ASCII,但我们经常使用其他字符集和编码(例如 UTF-8),它们可能有否定成员。

负值可以用三种方法中的一种来表示。

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

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

在这里,我们遇到了符号和幅度表示中的负零的问题。它无法通过无符号类型进行往返。因此,这样的实现不能轻易支持某些字符编码,如 UTF-8。不过,这对 ASCII 来说不是问题。

至于其他整数类型,这里的表示并不重要。当您使用 egint来表示 ASCII 值时,您通常对值感兴趣,而不是表示。您可以在 C 支持的所有整数类型之间安全地转换 0 到 127 的值。(其他整数类型可能有填充位,但除此之外,以上大部分内容也适用于它们;这无关紧要,因为正常编程几乎不会受到影响)。

使用不同字符表示的奇异平台无法支持标准 C,因此为此类平台编写可移植性并不是一个有意义的提议。

最后,如果您将 ASCII 替换为平台实际使用的任何基本字符集,情况也是如此,除了范围可能不同。


推荐阅读