为什么这个C程序编译没有错误?
我是C的初学者,我正在玩C.我输入了这样的C代码:
#include int main() { printf("hello world\n"); \ return 0; }
即使我使用\
,C编译器也不会抛出任何错误。 C语言中使用的符号是什么?
编辑:
即便如此:
"\n";
序列反斜杠 – 换行符在转换过程的早期阶段(阶段2)从代码中删除。 它曾经是如何在字符串连接之前创建长字符串文字,以及如何在多行上扩展宏。
参见§5.1.1.2C99标准的翻译阶段:
翻译语法规则的优先级由以下阶段指定。 5)
- 如果需要,物理源文件多字节字符以实现定义的方式映射到源字符集(为行尾指示符引入换行符)。 Trigraph序列由相应的单字符内部表示替换。
- 将删除紧跟着换行符的每个反斜杠字符(
\
)实例,拼接物理源行以形成逻辑源行。 只有任何物理源线上的最后一个反斜杠才有资格成为这种拼接的一部分。 非空的源文件应以换行符结尾,在进行任何此类拼接之前,该换行符不应立即以反斜杠字符开头。- 源文件被分解为预处理标记6)和空白字符序列(包括注释)。 源文件不应以部分预处理标记或部分注释结束。 每个注释都被一个空格字符替换。 保留换行符。 是否保留或替换为新行以外的每个非空白字符序列是由实现定义的。
- 执行预处理指令,扩展宏调用,并执行
_Pragma
一元运算符表达式。 如果通过标记连接(6.10.3.3)生成与通用字符名称的语法匹配的字符序列,则行为未定义。#include
预处理指令使得命名的头文件或源文件以递归方式从阶段1到阶段4进行处理。 然后删除所有预处理指令。- 字符常量和字符串文字中的每个源字符集成员和转义序列都将转换为执行字符集的相应成员; 如果没有相应的成员,则将其转换为null(宽)字符以外的实现定义成员。 7)
- 相邻的字符串文字标记是连接的。
- 分隔标记的空白字符不再重要。 每个预处理令牌都转换为令牌。 由此产生的标记在语法和语义上进行分析并翻译为翻译单元。
- 解析所有外部对象和函数引用。 链接库组件以满足对当前转换中未定义的函数和对象的外部引用。 所有这样的翻译器输出被收集到程序映像中,该程序映像包含在其执行环境中执行所需的信息。
5)实现应该表现得好像这些单独的阶段发生,即使许多通常在实践中折叠在一起。
6)如6.4中所述,将源文件的字符划分为预处理标记的过程取决于上下文。 例如,请参阅
#include
预处理指令中的<
处理。7)实现不需要将所有非对应的源字符转换为相同的执行字符。
如果在您的迷失反斜杠后有空白或任何其他字符,则会出现编译错误。 我们可以告诉您之后没有任何内容,因为您没有编译错误。
问题的另一部分,关于:
"\n";
是完全不同的。 这是一个简单的表达,没有副作用,因此对程序没有影响。 优化器将完全丢弃它。 当你写:
i = 1;
你有一个表达式,其值被丢弃; 评估其修改i
的副作用。
有时候,你会找到如下代码:
*ptr++;
编译器会警告您表达式的结果被丢弃; 表达式可以简化为:
ptr++;
并将在该计划中取得同样的效果。
当紧接着换行符时, \
会被预处理消耗,并导致下一个“物理”行连接到当前逻辑行。 这对于编写长预处理指令非常重要,这些指令必须全部在一条逻辑行上:
#define SHORT very log macro \ consisting of lots and \ lots of preprocessor \ tokens
如果删除反斜杠换行序列,则不再正确。 Unix文化中的一些其他语言具有类似的反斜杠行延续语法:从Bourne shell派生的POSIX shell语言,以及makefile。
$ this is \ one shell command
关于"\n";
,这是用于形成表达式语句的主要表达式。 在C语言中,表达式可以用作语句,并且它一直被利用。 例如,您的printf
调用是一个表达式语句。 printf("hello world\n")
是一个后缀表达式,它调用一个函数,获取一个返回值。 因为您将此表达式用作语句,所以返回值将被丢弃。 printf
的返回值表示打印了多少个字符,或者它是否完全成功,所以通过抛弃它,你的程序就会忘记printf
调用是否真的有效。
由于表达式语句的值被丢弃,如果这样的语句也没有副作用,那么这是一个无用的语句,它什么都不做(比如你的"\n"
)。 但是这种无用的表达陈述并不是错误的。 如果向编译器命令行添加警告选项,则可能会收到警告,例如“无效语句”或类似情况。
反斜杠\由C预处理器解释。 它保护其后续字符(案例中的新行字符)。
反斜杠只是转义下一个字符。 在这种情况下,可能是行结束(CR)字符。 完全合理。
反斜杠加上后面的内容是一个转义序列 ; “\ n”一起是换行符(打印换行符)。 另一个重要的是“\ t”,用于标签。