【问题标题】:Are trigraphs required to write a newline character in C99 using only ISO 646?仅使用 ISO 646 在 C99 中写入换行符是否需要三元组?
【发布时间】:2015-10-26 15:35:06
【问题描述】:

假设您正在使用 ISO 646 的不变集编写(可移植的)C99 代码。这意味着不能直接编写 \(反斜杠,反斜线,无论您如何命名)。例如,可以选择这样编写一个 Hello World 程序:

%:include <stdio.h>
%:include <stdlib.h>

int main()
<%
    fputs("Hello World!??/n", stdout);
    return EXIT_SUCCESS;
%>

但是,除了二合字母之外,我还使用了??/ 三合字母来写\ 字符。

根据我上面的假设,是否有可能

  1. 在字符串中包含'\n' 字符(在&lt;stdio.h&gt; 函数中转换为换行符)不使用三元组,或者
  2. 在不使用'\n' 字符的情况下将换行符写入FILE *

【问题讨论】:

  • 我不确定我是否理解。您的字符集没有反斜杠,但您不想使用它的三元组编写反斜杠?
  • @zneak:这是不可能的,因为标准要求这些字符存在。 (至少从大约 20 年以来,三合符是最多余的特征)。
  • @zneak 我必须使用三合字母的唯一地方(这与二合字母非常不同,因为它们是在不同的阶段翻译的)是写我唯一需要的反斜杠,即换行符。感觉有点不对劲。
  • 转义序列不是由库“翻译”,而是由编译器“翻译”。阅读port70.net/~nsz/c/c11/n1570.html#5.2.1
  • @Olaf,我不确定他是否提到过图书馆。

标签: c newline stdio trigraphs


【解决方案1】:

对于stdout,您可以只使用puts("") 来输出换行符。或者确实将原始程序中的fputs 替换为puts 并删除\n

如果您想将换行符放入一个变量中以便您可以用它做其他事情,我知道另一个标准函数可以免费为您提供:

int gimme_a_newline(void)
{
  time_t t = time(0);
  return strchr(ctime(&t), 0)[-1];
}

你可以说

fprintf(stderr, "Hello, world!%c", gimme_a_newline());

(我希望我使用的所有字符都是 ISO646 或二合字母可访问的。我发现很难获得 ISO646 中不包含哪些 ASCII 字符的简单列表。维基百科有一个颜色编码表,对比度不够在颜色之间让我知道是什么。)

【讨论】:

  • 哇 :) 只是说如果 OP 想要避免 ??/ 因为它只是“感觉不对”...... this hack 感觉如何?
  • 大声笑,当然可以 ;) ...你总是可以dup2()你的 fd 到STDOUT_FILENO,所以puts() 可以处理任何文件:)
  • 这也是 C 历史上唯一一次 ctime 的输出格式解决了问题而不是创建问题。现在希望gets是正确答案的后续问题。
  • 我不能不赞成这样一个聪明的黑客,即使感觉如此,如此错误。
  • @Rhymoid OTOH 我对这个奇怪但发人深省的问题和这个发人深省的聪明答案都投了赞成票——不管是不是傻。
【解决方案2】:

你的前提:

假设您在 ISO 646 的不变集合中编写(可移植的)C99 代码。这意味着不能直接编写 \(反斜杠,反斜线,无论您如何命名)。

值得怀疑。 C99 定义了“源”和“执行”字符集,并要求两者都包括反斜杠字符的表示(C99 5.2.1)。对于您所描述的努力,我能想象的唯一原因是尝试生成在机器之间移动时不需要字符集转码的源代码。然而,在这种情况下,选择 ISO 646 作为通用基准是很奇怪的。与使用与 ISO-8859 系列字符集不一致的 ISO 646 变体相比,您更有可能遇到 EBCDIC 机器。 (如果您可以假设 ISO 8859,那么反斜杠不会出现问题。)

尽管如此,如果您坚持编写 C 源代码而不使用文字反斜杠字符,那么该字符的三元组就是这样做的方法。这就是发明三字母组的目的。在字符常量和字符串文字中,您不能用其他任何东西替换\n 或其等效的三元组??/n,因为它取决于实现该代码的映射方式。特别是,假设它映射到换行符是不安全的(但是,它包含在 ISO 646 的不变字符中)。

更新:

你具体问是否可以

在不使用三元组的情况下在字符串中包含“\n”字符(在函数中转换为换行符),或者

不,这是不可能的,因为没有一个'\n' 字符。此外,这里似乎有点误解:字符或字符串文字中的\n 表示执行字符集中的一个 字符。因此,编译器负责该转换,而不是 stdio 函数。 stdio 函数的职责是通过编写旨在产生指定效果的字符或字符序列来处理输出中的该字符(“[m]将活动位置移动到下一行的初始位置”)。

你还问有没有可能

在 FILE * 中写入换行符而不使用 '\n' 字符?

这取决于你的意思。如果你想写一个你知道执行字符集中代码的字符,那么你可以写一个具有该数值的数字常量。特别是,如果您想写入具有编码值0xa(在执行字符集中)的字符,那么您可以这样做。例如,你可以

fputc(0xa, my_file);

但这并不一定会产生等同于

的结果
fputc('\n', my_file);

【讨论】:

  • “stdio 函数的职责是通过产生指定的效果来处理输出中的那个字符”甚至不是。这些函数只会将字符写入输出流。真正创造可见效果的是终端。
  • @FelixPalmen 我得看看,但我敢打赌标准库和终端之间的任何交互(以及后者的存在)完全是实现定义的。
  • @FelixPalmen,鉴于“文本文件中的外部表示不必与内部表示相同,并且超出 [C99 标准] 的范围”,我不得不说stdio 函数确实负责翻译。当然,这通常是身份转换。 stdio 函数负责的是尝试将该转换与任何特定的输出设备动态匹配。我已经更新了我的答案。
  • 如果您只是想避免看起来怪异的"??/n",您可以执行#define NL "??/n" 之类的操作,然后像"hello world" NL 一样使用它,因为C 连接字符串文字,中间没有任何内容.
  • @FelixPalmen 呵呵。我的理解不同:内部表示是标准库使用的(单个字符代码),而外部表示是您实际发送到存储系统或显示设备的表示。我想到了 DOS 在"\n"(文本模式流)和"\x0D\x0A"(二进制模式流)之间的转换。
【解决方案3】:

简短的回答是,是的,对于你想做的事情,你必须使用这个三元组。

即使有 \ 的二合字母,它在 字符串字面量 内也是无用的,因为二合字母必须是标记,它们被标记器识别,而三元组是经过预处理的,因此仍然可以在字符串文字等中使用。

仍然想知道为什么有人会以这种方式编码源代码今天 ... :o

【讨论】:

    【解决方案4】:
    1. 没有。 \n(或其等效的三元组)是换行符的可移植表示。
    2. 没有。您必须以某种方式表示文字换行符,而 \n(或它的三元组等价物)是唯一可移植的表示形式。

    很难找到使用三合字母或二合字母的 C 源代码!一些编译器(例如 GNU gcc)需要命令行选项来启用三元组的使用,并假定它们已被无意使用并在源代码中遇到它们时发出警告。

    编辑:我忘了puts("")。这是一种偷偷摸摸的方式,但仅适用于stdout

    【讨论】:

    • '\n' 没有三元组,但反斜杠有。三元组是替换某些单个字符,而不是转义序列。
    【解决方案5】:

    当然可以

    fputc(0x0A, file);
    

    【讨论】:

    • 虽然我的 源文件 可能是 ISO 646(至少,当我发布它们时),我怀疑 C99 标准保证目标架构上的 I/O 流使用相同的编码,或者像fgets 这样的函数将&lt;0A&gt; 解释为换行符。
    • 我仍然不明白为什么要使用它。通常,如果字符串文字或字符常量,您不会在外部使用反斜杠。即使是三元组序列也会更好。
    • @Olaf 第 5.2.2 节第 3 节说 \n 有一个实现定义的值,这意味着我不能只假设它是 0x0A
    • @Rhymoid:我没有提到 macic 编号。阅读我的第一条评论!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-02-06
    • 1970-01-01
    • 1970-01-01
    • 2021-11-02
    • 1970-01-01
    • 1970-01-01
    • 2014-02-20
    相关资源
    最近更新 更多