Indenting #defines
Asked Answered
S

9

126

I know that #defines, etc. are normally never indented. Why?

I'm working in some code at the moment which has a horrible mixture of #defines, #ifdefs, #elses, #endifs, etc. All these often mixed in with normal C code. The non-indenting of the #defines makes them hard to read. And the mixture of indented code with non-indented #defines is a nightmare.

Why are #defines typically not indented? Is there a reason one wouldn't indent (e.g. like this code below)?

#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
Starbuck answered 25/4, 2009 at 14:56 Comment(0)
C
122

Pre-ANSI C preprocessor did not allow for space between the start of a line and the "#" character; the leading "#" had to always be placed in the first column.

Pre-ANSI C compilers are non-existent these days. Use which ever style (space before "#" or space between "#" and the identifier) you prefer.

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

Crisper answered 25/4, 2009 at 15:36 Comment(0)
S
33

As some have already said, some Pre-ANSI compilers required the # to be the first char on the line but they didn't require the preprocessor directive to be attached to it, so indentation was made this way.

#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

I've often seen this style in old Unix headers but I hate it as the syntax coloring often fails on such code. I use a very visible color for pre-processor directives so that they stand out (they are at a meta-level so should not be part of the normal flow of code). You can even see that SO does not color the sequence in a useful manner.

Snooze answered 3/7, 2010 at 8:47 Comment(1)
I have often seen this style of blaming unconventional ways existing for incompetently special-cased tools failing to handle them, but I hate it, because people might have good reasons to do things such as putting the # as the first character (for example, it also makes preprocessor directives stand out better, even without syntax highlighting) and the real problem is syntax highlighting logic which doesn't actually match the syntax of what it's highlighting. (To be clear, I still +1'ed this answer, I just thought it was important to assert these points.)Inversion
D
21

Regarding the parsing of preprocessor directives, the C99 standard (and the C89 standard before it) were clear about the sequence of operations performed logically by the compiler. In particular, I believe it means that this code:

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

is equivalent to:

#include <stdio.h>

For better or worse, GCC 3.4.4 with '-std=c89 -pedantic' accepts the comment-laden line, at any rate. I'm not advocating that as a style - not for a second (it is ghastly). I just think that it is possible.

ISO/IEC 9899:1999 section 5.1.1.2 Translation phases says:

  1. [Character mapping, including trigraphs]

  2. [Line splicing - removing backslash newline]

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

  4. Preprocessing directives are executed, macro invocations are expanded, [...]

Section 6.10 Preprocessing directives says:

A preprocessing directive consists of a sequence of preprocessing tokens that begins with 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, and is ended by the next new-line character.

The only possible dispute is the parenthetical expression '(at the start of translation phase 4)', which could mean that the comments before the hash must be absent since they are not otherwise replaced by spaces until the end of phase 4.

As others have noted, the pre-standard C preprocessors did not behave uniformly in a number of ways, and spaces before and in preprocessor directives was one of the areas where different compilers did different things, including not recognizing preprocessor directives with spaces ahead of them.

It is noteworthy that backslash-newline removal occurs before comments are analyzed. Consequently, you should not end // comments with a backslash.

Decahedron answered 25/4, 2009 at 16:14 Comment(0)
P
7

I don't know why it's not more common. There are certainly times when I like to indent preprocessor directives.

One thing that keeps getting in my way (and sometimes convinces me to stop trying) is that many or most editors/IDEs will throw the directive to column 1 at the slightest provocation. Which is annoying as hell.

Pigmy answered 25/4, 2009 at 15:56 Comment(0)
Z
5

These days I believe this is mainly a choice of style. I think at one point in the distant past, not all compilers supported the notion of indenting preprocessor defines. I did some research and was unable to back up that assertion. But in any case, it appears that all modern compilers support the idea of indenting pre-processor macro. I do not have a copy of the C or C++ standard though so I do not know if this is standard behavior or not.

As to whether or not it's good style. Personally, I like the idea of keeping them all to the left. It gives you a consistent place to look for them. Yeah it can get annoying when there are very nested macros. But if you indent them, you'll eventually end up with even weirder looking code.

#if COND1
void foo() {
  #if COND2
  int i;
    #if COND3
  i = someFunction()
  cout << i << eol;
    #endif
  #endif
}
#endif
Zanthoxylum answered 25/4, 2009 at 15:19 Comment(4)
The reason this code looks weird is because you've created two "streams" of indentation. I would indent line 4 one more level, and i would indent lines 6 & 7 by two more levels.Cofsky
Totally agree. I sometimes even put braces so the #if's look just like the if's.Instability
I try very hard to arrange my code so that it has no #ifdef lines in the parts where I have actual code. Instead, if I need conditional stuff I either put it in factored out functions or factored out macros; it's a lot clearer that way I find (well, at least it is to me). Ideally, all those factored out parts will be in other files (headers or conditionally-compiled source files; the usual "condition" being what platform the code is being built for).Intwine
I would indent lines 4 one level, and lines 6 & 7 two levels.Starbuck
H
3

For the example you've given it may be appropriate to use indentation to make it clearer, seeing as you have such a complex structure of nested directives.

Personally I think it is useful to keep them not indented most of the time, because these directives operate separately from the rest of your code. Directives such as #ifdef are handled by the pre-processor, before the compiler ever sees your code, so a block of code after an #ifdef directive may not even be compiled.

Keeping directives visually separated from the rest of your code is more important when they are interspersed with code (rather than a dedicated block of directives, as in the example you give).

Halmstad answered 25/4, 2009 at 15:21 Comment(1)
From the IP's point of view, what's the difference between something that's not compiled and something that's not reached because of a jmp.Instability
F
3

In almost all the currently available C/CPP compilers it is not restricted. It's up to the user to decide how you want to align code. So happy coding.

Frore answered 21/11, 2019 at 15:23 Comment(1)
Decent answer. Could you improve it by adding some specific style guide reference?Puduns
L
2

I'm working in some code at the moment which has a horrible mixture of #defines, #ifdefs, #elses, #endifs, #etc. All these often mixed in with normal C code. The non-indenting of the #defines makes them hard to read. And the mixture of indented code with non-indented #defines is a nightmare.

A common solution is to comment the directives, so that you easily know what they refer to:

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

#ifndef FOO
/* a lot of code */
#endif /* not FOO */
Lotti answered 25/4, 2009 at 15:17 Comment(1)
I have seen that style, my boss uses it. And, like the rest of his code, it just makes a mess. Imagine removing all of the indentation from your normal if() statements and using those comments instead. You'll complain that you can't easily see what they refer to.Starbuck
P
0

I know this is old topic but I wasted couple of days searching for solution. I agree with initial post that intending makes code cleaner if you have lots of them (in my case I use directives to enable/disable verbose logging). Finally, I found solution here which works Visual Studio 2017

If you like to indent #pragma expressions, you can enable it under: Tools > Options > Text Editor > C/C++ > Formatting > Indentation > Position of preprocessor directives > Leave indented

The only problem left is that auto code layout fixed that formatting =(

Panther answered 25/10, 2020 at 8:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.