为什么这个C程序编译没有错误?

时间:2021-04-13 18:15:03

I'm a beginner in C, and I was playing with C. I typed a C code like this:

我是C的初学者,我正在玩C.我输入了这样的C代码:

#include <stdio.h>
int main()
{
    printf("hello world\n"); 
    \
    return 0;
}

Even though I used \ knowingly, the C compiler doesn't throw any error. What is this symbol used for in the C language?

即使我使用\知识,C编译器也不会抛出任何错误。 C语言中使用的符号是什么?

Edit:

Even this works:

即便如此:

"\n";

5 个解决方案

#1


11  

The sequence backslash-newline is removed from the code in a very early phase (phase 2) of the translation process. It used to be how you created long string literals before there was string concatenation, and is how you still extend macros over multiple lines.

序列反斜杠 - 换行符在转换过程的早期阶段(阶段2)从代码中删除。它曾经是如何在字符串连接之前创建长字符串文字,以及如何在多行上扩展宏。

See §5.1.1.2 Translation Phases of the C99 standard:

参见§5.1.1.2C99标准的翻译阶段:

The precedence among the syntax rules of translation is specified by the following phases.5)

翻译语法规则的优先级由以下阶段指定.5)

  1. Physical source file multibyte characters are mapped, in an implementation defined manner, to the source character set (introducing new-line characters for end-of-line indicators) if necessary. Trigraph sequences are replaced by corresponding single-character internal representations.
  2. 如果需要,物理源文件多字节字符以实​​现定义的方式映射到源字符集(为行尾指示符引入换行符)。 Trigraph序列由相应的单字符内部表示替换。

  3. Each instance of a backslash character (\) immediately followed by a new-line character is deleted, splicing physical source lines to form logical source lines. Only the last backslash on any physical source line shall be eligible for being part of such a splice. A source file that is not empty shall end in a new-line character, which shall not be immediately preceded by a backslash character before any such splicing takes place.
  4. 将删除紧跟着换行符的每个反斜杠字符(\)实例,拼接物理源行以形成逻辑源行。只有任何物理源线上的最后一个反斜杠才有资格成为这种拼接的一部分。非空的源文件应以换行符结尾,在进行任何此类拼接之前,该换行符不应立即以反斜杠字符开头。

  5. The source file is decomposed into preprocessing tokens6) and sequences of white-space characters (including comments). A source file shall not end in a partial preprocessing token or in a partial comment. Each comment is replaced by one space character. New-line characters are retained. Whether each nonempty sequence of white-space characters other than new-line is retained or replaced by one space character is implementation-defined.
  6. 源文件被分解为预处理标记6)和空白字符序列(包括注释)。源文件不应以部分预处理标记或部分注释结束。每个注释都被一个空格字符替换。保留换行符。是否保留或替换为新行以外的每个非空白字符序列是由实现定义的。

  7. Preprocessing directives are executed, macro invocations are expanded, and _Pragma unary operator expressions are executed. If a character sequence that matches the syntax of a universal character name is produced by token concatenation (6.10.3.3), the behavior is undefined. A #include preprocessing directive causes the named header or source file to be processed from phase 1 through phase 4, recursively. All preprocessing directives are then deleted.
  8. 执行预处理指令,扩展宏调用,并执行_Pragma一元运算符表达式。如果通过标记连接(6.10.3.3)生成与通用字符名称的语法匹配的字符序列,则行为未定义。 #include预处理指令使得命名的头文件或源文件以递归方式从阶段1到阶段4进行处理。然后删除所有预处理指令。

  9. Each source character set member and escape sequence in character constants and string literals is converted to the corresponding member of the execution character set; if there is no corresponding member, it is converted to an implementation defined member other than the null (wide) character.7)
  10. 字符常量和字符串文字中的每个源字符集成员和转义序列都将转换为执行字符集的相应成员;如果没有相应的成员,则将其转换为null(宽)字符以外的实现定义成员.7)

  11. Adjacent string literal tokens are concatenated.
  12. 相邻的字符串文字标记是连接的。

  13. White-space characters separating tokens are no longer significant. Each preprocessing token is converted into a token. The resulting tokens are syntactically and semantically analyzed and translated as a translation unit.
  14. 分隔标记的空白字符不再重要。每个预处理令牌都转换为令牌。由此产生的标记在语法和语义上进行分析并翻译为翻译单元。

  15. All external object and function references are resolved. Library components are linked to satisfy external references to functions and objects not defined in the current translation. All such translator output is collected into a program image which contains information needed for execution in its execution environment.
  16. 解析所有外部对象和函数引用。链接库组件以满足对当前转换中未定义的函数和对象的外部引用。所有这样的翻译器输出被收集到程序映像中,该程序映像包含在其执行环境中执行所需的信息。

5) Implementations shall behave as if these separate phases occur, even though many are typically folded together in practice.

5)实现应该表现得好像这些单独的阶段发生,即使许多通常在实践中折叠在一起。

6) As described in 6.4, the process of dividing a source file’s characters into preprocessing tokens is context-dependent. For example, see the handling of < within a #include preprocessing directive.

6)如6.4中所述,将源文件的字符划分为预处理标记的过程取决于上下文。例如,请参阅#include预处理指令中的 <处理。< p>

7) An implementation need not convert all non-corresponding source characters to the same execution character.

7)实现不需要将所有非对应的源字符转换为相同的执行字符。

If you had a blank or any other character after your stray backslash, you would have a compilation error. We can tell that you don't have anything after it because you don't have a compilation error.

如果在您的迷失反斜杠后有空白或任何其他字符,则会出现编译错误。我们可以告诉您之后没有任何内容,因为您没有编译错误。


The other part of your question, about:

问题的另一部分,关于:

"\n";

is quite different. It is a simple expression that has no side-effects and therefore no effect on the program. The optimizer will completely discard it. When you write:

是完全不同的。这是一个简单的表达,没有副作用,因此对程序没有影响。优化器将完全丢弃它。当你写:

i = 1;

you have an expression with a value that is discarded; it is evaluated for its side-effect of modifying i.

你有一个表达式,其值被丢弃;评估其修改i的副作用。

Sometimes, you'll find code like:

有时候,你会找到如下代码:

*ptr++;

The compiler will warn you that the result of the expression is discarded; the expression can be simplified to:

编译器会警告您表达式的结果被丢弃;表达式可以简化为:

ptr++;

and will achieve the same effect in the program.

并将在该计划中取得同样的效果。

#2


4  

The \, when immediately followed by a newline, is consumed by preprocessing and causes the next "physical" line to be joined to the current logical line. This is very important for writing long preprocessing directives, which have to be all on one logical line:

当紧接着换行符时,\会被预处理消耗,并导致下一个“物理”行连接到当前逻辑行。这对于编写长预处理指令非常重要,这些指令必须全部在一条逻辑行上:

#define SHORT very log macro \
   consisting of lots and \
   lots of preprocessor \
   tokens

If you remove the backslash-newline sequences, it is no longer correct. Some other languages from the Unix culture have a similar backslash line continuation syntax: the POSIX shell language derived from the Bourne shell, and also makefiles.

如果删除反斜杠换行序列,则不再正确。 Unix文化中的一些其他语言具有类似的反斜杠行延续语法:从Bourne shell派生的POSIX shell语言,以及makefile。

$ this is \
one shell command

About "\n";, that is a primary expression used to form an expression-statement. In C, expressions can be used as statements, and this is exploited all the time. Your printf call, for instance, is an expression statement. printf("hello world\n") is a postfix expression which calls a function, obtaining a return value. Because you used this expression as a statement, the return value is thrown away. The return value of printf indicates how many characters were printed, or whether it was successful at all, so by throwing it away, your program makes itself oblivious to whether the printf call actually worked.

关于“\ n”;,这是用于形成表达式语句的主表达式。在C语言中,表达式可以用作语句,并且它一直被利用。例如,您的printf调用是一个表达式语句。 printf(“hello world \ n”)是一个后缀表达式,它调用一个函数,获取一个返回值。因为您将此表达式用作语句,所以返回值将被丢弃。 printf的返回值表示打印了多少个字符,或者它是否完全成功,所以通过抛弃它,你的程序就会忘记printf调用是否真的有效。

Since the value of an expression-statement is discarded, if such a statement also has no side effects, it is a useless statement which does nothing (like your "\n"). But such useless expression statements are not erroneous. If you add warning options to your compiler command line you might get a warning such as "statement with no effect" or something like that.

由于表达式语句的值被丢弃,如果这样的语句也没有副作用,那么这是一个无用的语句,它什么都不做(比如你的“\ n”)。但是这种无用的表达陈述并不是错误的。如果向编译器命令行添加警告选项,则可能会收到警告,例如“无效语句”或类似情况。

#3


0  

The backslash \ get interpreted by the C preprocessor. It protect its following character (the new line character on your case).

反斜杠\由C预处理器解释。它保护其后续字符(案例中的新行字符)。

#4


0  

The backslash is simply escaping the next character. In this case, probably a line end (CR) character. Perfectly reasonable.

反斜杠只是转义下一个字符。在这种情况下,可能是行结束(CR)字符。完全合理。

#5


0  

The backslash plus what is following it is an escape sequence; "\n" together is the newline character (prints a newline). Another important one is "\t", for tab.

反斜杠加上后面的内容是一个转义序列; “\ n”一起是换行符(打印换行符)。另一个重要的是“\ t”,用于标签。

#1


11  

The sequence backslash-newline is removed from the code in a very early phase (phase 2) of the translation process. It used to be how you created long string literals before there was string concatenation, and is how you still extend macros over multiple lines.

序列反斜杠 - 换行符在转换过程的早期阶段(阶段2)从代码中删除。它曾经是如何在字符串连接之前创建长字符串文字,以及如何在多行上扩展宏。

See §5.1.1.2 Translation Phases of the C99 standard:

参见§5.1.1.2C99标准的翻译阶段:

The precedence among the syntax rules of translation is specified by the following phases.5)

翻译语法规则的优先级由以下阶段指定.5)

  1. Physical source file multibyte characters are mapped, in an implementation defined manner, to the source character set (introducing new-line characters for end-of-line indicators) if necessary. Trigraph sequences are replaced by corresponding single-character internal representations.
  2. 如果需要,物理源文件多字节字符以实​​现定义的方式映射到源字符集(为行尾指示符引入换行符)。 Trigraph序列由相应的单字符内部表示替换。

  3. Each instance of a backslash character (\) immediately followed by a new-line character is deleted, splicing physical source lines to form logical source lines. Only the last backslash on any physical source line shall be eligible for being part of such a splice. A source file that is not empty shall end in a new-line character, which shall not be immediately preceded by a backslash character before any such splicing takes place.
  4. 将删除紧跟着换行符的每个反斜杠字符(\)实例,拼接物理源行以形成逻辑源行。只有任何物理源线上的最后一个反斜杠才有资格成为这种拼接的一部分。非空的源文件应以换行符结尾,在进行任何此类拼接之前,该换行符不应立即以反斜杠字符开头。

  5. The source file is decomposed into preprocessing tokens6) and sequences of white-space characters (including comments). A source file shall not end in a partial preprocessing token or in a partial comment. Each comment is replaced by one space character. New-line characters are retained. Whether each nonempty sequence of white-space characters other than new-line is retained or replaced by one space character is implementation-defined.
  6. 源文件被分解为预处理标记6)和空白字符序列(包括注释)。源文件不应以部分预处理标记或部分注释结束。每个注释都被一个空格字符替换。保留换行符。是否保留或替换为新行以外的每个非空白字符序列是由实现定义的。

  7. Preprocessing directives are executed, macro invocations are expanded, and _Pragma unary operator expressions are executed. If a character sequence that matches the syntax of a universal character name is produced by token concatenation (6.10.3.3), the behavior is undefined. A #include preprocessing directive causes the named header or source file to be processed from phase 1 through phase 4, recursively. All preprocessing directives are then deleted.
  8. 执行预处理指令,扩展宏调用,并执行_Pragma一元运算符表达式。如果通过标记连接(6.10.3.3)生成与通用字符名称的语法匹配的字符序列,则行为未定义。 #include预处理指令使得命名的头文件或源文件以递归方式从阶段1到阶段4进行处理。然后删除所有预处理指令。

  9. Each source character set member and escape sequence in character constants and string literals is converted to the corresponding member of the execution character set; if there is no corresponding member, it is converted to an implementation defined member other than the null (wide) character.7)
  10. 字符常量和字符串文字中的每个源字符集成员和转义序列都将转换为执行字符集的相应成员;如果没有相应的成员,则将其转换为null(宽)字符以外的实现定义成员.7)

  11. Adjacent string literal tokens are concatenated.
  12. 相邻的字符串文字标记是连接的。

  13. White-space characters separating tokens are no longer significant. Each preprocessing token is converted into a token. The resulting tokens are syntactically and semantically analyzed and translated as a translation unit.
  14. 分隔标记的空白字符不再重要。每个预处理令牌都转换为令牌。由此产生的标记在语法和语义上进行分析并翻译为翻译单元。

  15. All external object and function references are resolved. Library components are linked to satisfy external references to functions and objects not defined in the current translation. All such translator output is collected into a program image which contains information needed for execution in its execution environment.
  16. 解析所有外部对象和函数引用。链接库组件以满足对当前转换中未定义的函数和对象的外部引用。所有这样的翻译器输出被收集到程序映像中,该程序映像包含在其执行环境中执行所需的信息。

5) Implementations shall behave as if these separate phases occur, even though many are typically folded together in practice.

5)实现应该表现得好像这些单独的阶段发生,即使许多通常在实践中折叠在一起。

6) As described in 6.4, the process of dividing a source file’s characters into preprocessing tokens is context-dependent. For example, see the handling of < within a #include preprocessing directive.

6)如6.4中所述,将源文件的字符划分为预处理标记的过程取决于上下文。例如,请参阅#include预处理指令中的 <处理。< p>

7) An implementation need not convert all non-corresponding source characters to the same execution character.

7)实现不需要将所有非对应的源字符转换为相同的执行字符。

If you had a blank or any other character after your stray backslash, you would have a compilation error. We can tell that you don't have anything after it because you don't have a compilation error.

如果在您的迷失反斜杠后有空白或任何其他字符,则会出现编译错误。我们可以告诉您之后没有任何内容,因为您没有编译错误。


The other part of your question, about:

问题的另一部分,关于:

"\n";

is quite different. It is a simple expression that has no side-effects and therefore no effect on the program. The optimizer will completely discard it. When you write:

是完全不同的。这是一个简单的表达,没有副作用,因此对程序没有影响。优化器将完全丢弃它。当你写:

i = 1;

you have an expression with a value that is discarded; it is evaluated for its side-effect of modifying i.

你有一个表达式,其值被丢弃;评估其修改i的副作用。

Sometimes, you'll find code like:

有时候,你会找到如下代码:

*ptr++;

The compiler will warn you that the result of the expression is discarded; the expression can be simplified to:

编译器会警告您表达式的结果被丢弃;表达式可以简化为:

ptr++;

and will achieve the same effect in the program.

并将在该计划中取得同样的效果。

#2


4  

The \, when immediately followed by a newline, is consumed by preprocessing and causes the next "physical" line to be joined to the current logical line. This is very important for writing long preprocessing directives, which have to be all on one logical line:

当紧接着换行符时,\会被预处理消耗,并导致下一个“物理”行连接到当前逻辑行。这对于编写长预处理指令非常重要,这些指令必须全部在一条逻辑行上:

#define SHORT very log macro \
   consisting of lots and \
   lots of preprocessor \
   tokens

If you remove the backslash-newline sequences, it is no longer correct. Some other languages from the Unix culture have a similar backslash line continuation syntax: the POSIX shell language derived from the Bourne shell, and also makefiles.

如果删除反斜杠换行序列,则不再正确。 Unix文化中的一些其他语言具有类似的反斜杠行延续语法:从Bourne shell派生的POSIX shell语言,以及makefile。

$ this is \
one shell command

About "\n";, that is a primary expression used to form an expression-statement. In C, expressions can be used as statements, and this is exploited all the time. Your printf call, for instance, is an expression statement. printf("hello world\n") is a postfix expression which calls a function, obtaining a return value. Because you used this expression as a statement, the return value is thrown away. The return value of printf indicates how many characters were printed, or whether it was successful at all, so by throwing it away, your program makes itself oblivious to whether the printf call actually worked.

关于“\ n”;,这是用于形成表达式语句的主表达式。在C语言中,表达式可以用作语句,并且它一直被利用。例如,您的printf调用是一个表达式语句。 printf(“hello world \ n”)是一个后缀表达式,它调用一个函数,获取一个返回值。因为您将此表达式用作语句,所以返回值将被丢弃。 printf的返回值表示打印了多少个字符,或者它是否完全成功,所以通过抛弃它,你的程序就会忘记printf调用是否真的有效。

Since the value of an expression-statement is discarded, if such a statement also has no side effects, it is a useless statement which does nothing (like your "\n"). But such useless expression statements are not erroneous. If you add warning options to your compiler command line you might get a warning such as "statement with no effect" or something like that.

由于表达式语句的值被丢弃,如果这样的语句也没有副作用,那么这是一个无用的语句,它什么都不做(比如你的“\ n”)。但是这种无用的表达陈述并不是错误的。如果向编译器命令行添加警告选项,则可能会收到警告,例如“无效语句”或类似情况。

#3


0  

The backslash \ get interpreted by the C preprocessor. It protect its following character (the new line character on your case).

反斜杠\由C预处理器解释。它保护其后续字符(案例中的新行字符)。

#4


0  

The backslash is simply escaping the next character. In this case, probably a line end (CR) character. Perfectly reasonable.

反斜杠只是转义下一个字符。在这种情况下,可能是行结束(CR)字符。完全合理。

#5


0  

The backslash plus what is following it is an escape sequence; "\n" together is the newline character (prints a newline). Another important one is "\t", for tab.

反斜杠加上后面的内容是一个转义序列; “\ n”一起是换行符(打印换行符)。另一个重要的是“\ t”,用于标签。