Does '#'-character have to be at the start of a line in the C preprocessor? [duplicate]

試著忘記壹切 提交于 2021-01-02 05:19:06

问题


I have programmed C for quite a while now. During this time I have learned that it is a common convention to put the "#"-character that comes before preprocessor-directives at column one.

Example:

 #include <stdio.h>

 int main(void) {
 #ifdef MACRO1
 #ifdef MACRO2
      puts("defined(MACRO1) && defined(MACRO2)");
 #else
      puts("defined(MACRO1)");
 #endif
 #else
      puts("!defined(MACRO1)");
 #endif
      return 0;
 }

When people indent their preprocessor directives they usually do it like this:

 #include <stdio.h>

 int main(void) {
 #ifdef MACRO1
 # ifdef MACRO2
     puts("defined(MACRO1) && defined(MACRO2)");
 # else
     puts("defined(MACRO1)");
 # endif
 #else
     puts("!defined(MACRO1)");
 #endif
     return 0;
 }

I do not think that I have ever seen anyone format it like this:

 #include <stdio.h>

 int main(void) {
 #ifdef MACRO1
  #ifdef MACRO2
     puts("defined(MACRO1) && defined(MACRO2)");
  #else
     puts("defined(MACRO1)");
  #endif
 #else
     puts("!defined(MACRO1)");
 #endif
     return 0;
 }

My question is if the C language standard demands that the #-character should be in column one.

So is the third option above even legal?

If all above cases are legal then I want to know if this is legal.

 #include <stdio.h>

 int main(void) {
 #ifdef MACRO
     puts("defined(MACRO)");
 /* Now there are other characters before the `#` */ #endif
     return 0;
 }

Here is the #endif no longer on the "start" of the line because there are other non-whitespace characters in the way.

What seems weird about the last example is that Vim text-editor does not highlight the #endif that comes after the comment.

Screenshot

All these examples I have given compiles without any warnings using gcc with the -Wall -pedantic flags turned on (including the last one with a comment before #endif).

Note that I am just curious about the syntax. I always put #-character at column one like everyone else when I program. I would never write things like ++i; #endif in serious projects.


回答1:


In some pre-standard C preprocessors (meaning before 1989), the preprocessors only recognized # at the beginning of the line.

Since the C89/C90 standards required the preprocessor to recognize the # as the first non-blank character on the line (and the C99 and C11 standards do too), it is now perfectly legitimate to indent the directives, and it has been practical for even portable code to do so for all of this millennium.

In ISO/IEC 9899:2011 (the C11 standard), Section 6.10 Preprocessing directives says:

A preprocessing directive consists of a sequence of preprocessing tokens that satisfies the following constraints: The first token in the sequence is a # preprocessing token that (at the start of translation phase 4) is either the first character in the source file (optionally after white space containing no new-line characters) or that follows white space containing at least one new-line character.

The translation phases are defined in section 5.1.1.2 Translation phases.

  1. The source file is decomposed into preprocessing tokens 7) 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.

  2. 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.

Occasionally, you will find coding standards originating from the 1980s which still stipulate '# at start of line'.

I usually don't indent preprocessor directives, but it is legitimate to do so.




回答2:


No, and here's a quote from the C standard to go with it (from section 6.10):

A preprocessing directive consists of a sequence of preprocessing tokens that satisfies the following constraints: The first token in the sequence is a # preprocessing token that (at the start of translation phase 4) is either the first character in the source file (optionally after white space containing no new-line characters) or that follows white space containing at least one new-line character.

So it's a # at the start of the file or after some whitespace that contains at least one new-line character.

This means:

# define foo
  # define bar

foo's definition is fine because the # is the first token in the file. bar's definition is fine because the # "follows white space containing at least one new-line character."



来源:https://stackoverflow.com/questions/27871083/does-character-have-to-be-at-the-start-of-a-line-in-the-c-preprocessor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!