2009-04-25 49 views
79

我知道#define s等通常不会缩进。为什么?缩进#defines

我在一些代码在其中有#define S,#ifdef S,#else S,#endif S等可怕的混合工作的时刻,所有这些往往与普通的C代码混合在一起。 #define的非缩进使得它们难以阅读。缩进代码与非缩进#define s的混合是一场噩梦。

不缩进#define s的好处是什么?如果我缩进它,它会让我变成一个坏人吗?这不是更好吗?

#ifdef SDCC 
    #if DEBUGGING == 1 
     #if defined (pic18f2480) 
      #define FLASH_MEMORY_END 0x3DC0 
     #elif defined (pic18f2580) 
      #define FLASH_MEMORY_END 0x7DC0 
     #else 
      #error "Can't set up flash memory end!" 
     #endif 
    #else 
     #if defined (pic18f2480) 
      #define FLASH_MEMORY_END 0x4000 
     #elif defined (pic18f2580) 
      #define FLASH_MEMORY_END 0x8000 
     #else 
      #error "Can't set up flash memory end!" 
     #endif 
    #endif 
#else 
    #if DEBUGGING == 1 
     #define FLASH_MEMORY_END 0x7DC0 
    #else 
     #define FLASH_MEMORY_END 0x8000 
    #endif 
#endif 

回答

84

预ANSI C预处理器不允许在行首和“#”字符之间留出空格;领先的“#”必须始终放在第一列。

这些日子以前,ANSI-C以前的编译器不存在。使用你喜欢的风格(“#”之前的空格或“#”和标识符之间的空格)。

http://www.delorie.com/gnu/docs/gcc/cpp_48.html

2

我在一些代码在其中有#define语句,的#ifdefs,#elses,#endifs,#etc一个可怕的混合工作的时刻。所有这些经常混入正常的C代码。非定义的#defines使他们很难阅读。缩进代码与非缩进#defines的混合是一场噩梦。

常见的解决方案是评论的指令,让你轻松知道他们是指:

#ifdef FOO 
/* a lot of code */ 
#endif /* FOO */ 

#ifndef FOO 
/* a lot of code */ 
#endif /* not FOO */ 
+3

我已经看到了这种风格,我的老板使用它。而且,就像他的其他代码一样,它只是一团糟。想象一下,从正常的if()语句中删除所有缩进,并改用这些注释。你会抱怨你不能轻易看到他们指的是什么。 – Rocketmagnet 2010-09-14 20:57:24

4

这些天,我相信这是主要的风格选择。我想认为在遥远的过去的一个点,并不是所有编译器都支持缩进预处理器定义的概念。我做了一些研究,但无法支持这一说法。但无论如何,似乎所有现代编译器都支持缩进预处理器宏的想法。我没有C或C++标准的副本,但我不知道这是否是标准行为。

至于它是不是很好的风格。就我个人而言,我喜欢把它们全部留在左边的想法。它给你一个寻找它们的地方。是的,当有非常嵌套的宏时它会变得烦人。但是如果你缩进它们,你最终会得到更奇怪的代码。

#if COND1 
void foo() { 
    #if COND2 
    int i; 
    #if COND3 
    i = someFunction() 
    cout << i << eol; 
    #endif 
    #endif 
} 
#endif 
+10

此代码看起来很奇怪的原因是因为您创建了两个缩进“流”。我会将第4行缩进一个级别,并且我会通过两个级别缩进第6和第7行。 – 2009-10-15 20:58:48

+2

完全同意。 我有时甚至把大括号这样#if看起来就像if。 – baash05 2010-03-10 05:21:11

4

因为你已经给你有嵌套的指令如此复杂的结构,它可适当使用缩进,使之更清晰,看到的例子。

就我个人而言,我认为让它们大部分时间不缩进是很有用的,因为这些指令独立于其他代码运行。指令如#ifdef在编译器看到您的代码之前由预处理器处理,因此#ifdef指令后面的代码块可能甚至不是编译的

将代码与代码的其余部分保持可视地分离时,如果它们之间散布代码(而不是专用的指令块,如您提供的示例中),则更重要。

4

我不知道为什么这不是更常见。当然我喜欢缩进预处理指令。这总是阻碍着我的方式(有时说服我停止尝试)

一件事是,许多或大部分编辑/ IDE中会抛出指令列1在丝毫挑衅。这是讨厌的地狱。

14

关于预处理器指令的解析,C99标准(和收到C89基准)为明确的操作顺序由编译器执行的逻辑。特别是,我相信它意味着这个代码:

/* */ # /* */ include /* */ <stdio.h> /* */ 

等同于:

#include <stdio.h> 

对于更好或更坏,GCC 3.4.4 '-std = C89 -pedantic' 接受评论无论如何,都需要拉线。我不是主张这是一种风格 - 不是一秒钟(这很可怕)。我只是认为这是可能的。

ISO/IEC 9899:1999部分5.1.1.2翻译阶段表示:

  1. [字符映射,包括三合字母]

  2. [行拼接 - 除去反斜杠换行符]

  3. 源文件被分解成预处理标记和 空白字符(包括注释)序列。源文件不得以 部分预处理令牌或部分注释结束。每个评论由 替换为一个空格字符。换行符保留。是否保留每个非空的 序列的空白字符而不是换行符,或者由 替代,一个空格字符是实现定义的。

  4. 预处理指令被执行时,宏调用被扩展,[...]

6.10节预处理指令表示:

预处理指令由预处理的序列的令牌与 开头的#预处理令牌(在翻译阶段4的开始)或者是源文件中的第一个字符 (WHI之后任选地te空间不包含换行字符),或者 跟随包含至少一个换行符的空格,并以下一个 换行符结束。

唯一可能的争议括号表达式“(在翻译阶段4的开始)”,这可能意味着散列之前的评论必须是不存在的,因为他们没有其他用空格代替,直到结束阶段4。如其他人已经指出的那样,预标准C预处理器在许多方面的表现并不一致,并且在预处理器指令之前和之前的空格是不同编译器做了不同事情的区域之一,包括不识别预处理器指令他们前面的空间。

值得注意的是,在分析注释之前会发生反斜杠 - 换行符删除。 因此,您不应该用反斜杠结束//注释。

20

正如一些人已经说过的,一些Pre-ANSI编译器要求#是该行的第一个字符,但他们不需要将de预处理指令附加到它上面,所以缩进就是这样完成的。

#ifdef SDCC 
# if DEBUGGING == 1 
# if defined (pic18f2480) 
#  define FLASH_MEMORY_END 0x3DC0 
# elif defined (pic18f2580) 
#  define FLASH_MEMORY_END 0x7DC0 
# else 
#  error "Can't set up flash memory end!" 
# endif 
# else 
# if defined (pic18f2480) 
#  define FLASH_MEMORY_END 0x4000 
# elif defined (pic18f2580) 
#  define FLASH_MEMORY_END 0x8000 
# else 
#  error "Can't set up flash memory end!" 
# endif 
# endif 
#else 
# if DEBUGGING == 1 
# define FLASH_MEMORY_END 0x7DC0 
# else 
# define FLASH_MEMORY_END 0x8000 
# endif 
#endif 

我经常看到这种风格在旧的Unix头,但我讨厌它的语法着色往往不能在此类代码。我对预处理器指令使用了非常明显的颜色,以便它们脱颖而出(它们处于元级别,因此不应该成为正常代码流的一部分)。 你甚至可以看到SO不会以有用的方式给序列着色。