【问题标题】:Does the underlying character set depend only on the C implementation?底层字符集是否仅取决于 C 实现?
【发布时间】:2013-03-06 15:13:43
【问题描述】:

许多文本警告将char 值作为整数处理是不可移植的,例如假设 'A' 的值为 65(如 ASCII)。

但是是什么决定了这个字符集是 ASCII(或扩展形式)还是其他字符集?是操作系统决定的,还是编译器决定的?我假设这不依赖于硬件。

例如,Intel PC 是否可以具有诸如 EBCDIC 之类的字符集(理论上)?在 Linux/Unix 中更改 LANG 环境变量是否会更改 C 程序的基本字符集的值(如果随后重新编译)?

(编辑:我现在看到 Linux 中的各种非拉丁字符集都具有相同的基本 ASCII 代码,例如 KOI8-U - 我假设存在与 ASCII 不兼容的字符集的变体)

【问题讨论】:

  • 我认为这是实现定义的。
  • 编译器决定。当然,一些决定会使其这样的编译器变得不那么有用。
  • 当然,任何事情都可能发生。真正的问题是,这会发生吗。

标签: c ascii


【解决方案1】:

标准不关心任何这些细节,就它而言,只有“实现”。

在实践中,硬件和操作系统都可以指定该平台上的 C 实现预期使用的实现细节,或者如果它们想要与系统功能互操作,它们是必需使用的(也就是说,随操作系统或硬件提供的代码)。所以我们经常说,“在 Win32 上,sizeof(void*) == 4”。不过,这是一种简写,因为有人可以,如果他们愿意,编写一个在 32 位 Windows 上运行并具有不同指针大小的 C 实现。我们真正的意思是,“在 Win32 ABI 中,sizeof(void*) == 4 和在 Win32 上运行的不遵循 Win32 ABI 的 C 实现被排除在考虑之外”。

因此,实现可以做任何他们喜欢的事情,只要他们不介意他们是否可以(例如)使用遵循系统约定的 dll。可以根据编译器和标准库的编写者的喜好来定义字符集,仅受标准中的内容限制。

也就是说,字符文字的值是编译时常量。这告诉您基本执行字符集在运行时无法更改。

此外,如果它依赖于环境变量,那么确保程序以与编译时相同的值运行将是某人的责任。这对用户来说非常不友好,但该标准实际上并没有禁止某人编写对程序运行方式有特殊限制的 C 实现。

【讨论】:

  • 我关于环境变量的问题是这样的——假设 Linux 有可用的字符集不是基于 ASCII 的(通过 LANG 变量),如果你用 ASCII 字符集编译了一个程序,然后在同一个操作系统中再次使用非 ASCII 字符集,你会得到不同的常量吗?
  • @teppic:如果你有一个编译器可以让你改变字符集,那么是的,你会得到不同的值。如果 gcc 在某处有 EBCDIC 选项,我不会感到惊讶。关键是,如果您针对使用 ASCII 的标准库运行具有非 ASCII 字符集的程序,那么例如 isspace 可能无法工作。
  • 好的。我想我想知道您是否最终会使用相同的操作系统根据区域设置生成(默认情况下)不同的代码。例如如果有人正在使用与 ASCII 不兼容的语言环境运行 Linux,该实现是否仍将只使用 ASCII 值,或者依赖于 ASCII 值的代码是否会中断。
  • @teppic:没有与 ASCII 不兼容的 Linux 语言环境,因此不会出现问题。但是,扩展执行字符集可以更改(以及多字节编码)。如果您的代码中嵌入了“错误”编码的字符串,那么当您更改语言环境时,它们会出现异常行为。但是基本字符集是一个二进制兼容性问题,改变它就像试图改变int 的大小或char 的签名(顺便说一句,gcc 确实有一个选项)。它变成了一个“不同”的 C 实现。
  • @SteveJessop:谢谢。我没有意识到所有 Linux 字符集都与 ASCII 兼容(如果系统库依赖它,这将是有意义的)。我认为这对于基本上任何使用 ASCII 兼容字符集的 Unix 实现都是正确的。
【解决方案2】:

C 标准是这样说的:

C99 中的§5.2.1/1

应定义两组字符及其相关的整理顺序: 写入了哪些源文件(源字符集),以及在 执行环境(执行字符集)。每组又分为一个 基本字符集,其内容由本节给出,以及一组零个或多个 特定于语言环境的成员(不是基本字符集的成员)称为 扩展字符。组合集也称为扩展字符集。这 执行字符集成员的值是实现定义的

在启动时编译器必须使用 C 语言环境,它只会在调用setlocale(LC_ALL, ""); 时选择操作系统的语言环境。

【讨论】:

  • 关于字符集是否依赖于 C 实现的问题,这说明了什么?
  • @EricPostpischil “实现定义”意味着它取决于实现。
  • 我要问的是为什么提到操作系统的语言环境是相关的。你是想说切换到操作系统的语言环境可以改变 C 实现对字符集的定义吗?那我就不同意了;操作系统的语言环境是实现的一部分。如果您只是说可以更改语言环境而不是说确实更改了字符集的实现定义,那么我看不到重点;谈论区域设置没有提供与问题相关的任何信息。
  • @EricPostpischil:不管 Tony 是否说,是的,更改语言环境可以更改字符集、哪些字符是有效的、如何解释它们等等。
  • @JerryCoffin:字符集是否改变不是问题。问题是 C 实现是决定字符集(包括更改)还是其他因素影响它。
【解决方案3】:

编译器清楚地确定使用哪个源和执行字符集,因为可能会发生交叉编译(例如,在使用 ASCII 的 Linux 机器上为使用 EBCDIC 的 IBM 大型机编译代码)。

【讨论】:

  • 那么编译器确定所有 x86 Linux 代码都使用 ASCII,而这是在实现中设置的?使用不基于 ASCII 的字符集的 x86 Linux 机器呢?
  • @teppic "所以编译器确定所有 x86 Linux 代码都使用 ASCII,并且在实现中设置了?" 我没有这么说;我是在举一个例子。你指的是哪个编译器? “使用不基于 ASCII 的字符集的 x86 Linux 机器怎么样?” 我认为这种配置对于使用 ASCII 字符集的代码没有任何用处,没有任何转换机制。
  • @modifiablelvalue ,所以您暗示您可以在 x86 linux 上编译使用 EBCDIC 的 IBM 代码?
  • @BarathBushan 这样的编译器将是一个符合 C 的翻译器。当然。
  • @modifiablelvalue , 是的,我想通了,所以简而言之,即使有系统特定的编码,所有系统都支持 ASCII 的原生形式,无需任何自定义
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-15
  • 1970-01-01
  • 2012-07-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多