#definesのインデント


99

そんなこと知ってる #defineの、などが正常にインデントされることはありません。どうして?

私は現在、#defines、#ifdefs、#elses、#endifsなどの恐ろしい混合があるいくつかのコードで作業しています。これらすべては、通常のCコードとよく混ざっています。#definesをインデントしないと、読みにくくなります。そして、インデントされたコードとインデントされていない#definesの混在は悪夢です。

#definesをインデントしないことの利点は何ですか?インデントすると悪い人になりますか?これはもっといいですか?

#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

回答:


103

ANSI C以前のプリプロセッサでは、行頭と「#」文字の間にスペースがありませんでした。先頭の「#」は常に最初の列に配置する必要がありました。

最近のANSI Cコンパイラは存在しません。好みのスタイル(「#」の前のスペースまたは「#」と識別子の間のスペース)を使用します。

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


26

一部の人がすでに述べたように、一部のPre-ANSIコンパイラでは、#を行の最初の文字にする必要がありましたが、プリプロセッサディレクティブを付加する必要がなかったため、インデントはこのように行われました。

#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がシーケンスを便利な方法で色付けしないこともわかります。


16

プリプロセッサディレクティブの解析に関して、C99標準(およびその前のC89標準)は、コンパイラによって論理的に実行される操作のシーケンスについて明確でした。特に、このコードは次のことを意味すると考えています。

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

以下と同等です。

#include <stdio.h>

良くも悪くも、 '-std = c89 -pedantic'を指定したGCC 3.4.4は、とにかくコメントを含む行を受け入れます。私はそれをスタイルとして主張しているのではありません-一瞬ではなく(それは恐ろしいことです)。それは可能だと思います。

ISO / IEC 9899:1999セクション5.1.1.2の翻訳フェーズでは、次のように述べています。

  1. [3文字表記を含む文字マッピング]

  2. [ラインスプライシング-バックスラッシュ改行の削除]

  3. ソースファイルは、前処理トークンと空白文字のシーケンス(コメントを含む)に分解されます。ソースファイルは、部分的な前処理トークンまたは部分的なコメントで終わってはなりません。各コメントは1つのスペース文字に置き換えられます。改行文字は保持されます。改行以外の空白でない空白文字の各シーケンスを保持するか、1つの空白文字で置き換えるかは、実装によって定義されます。

  4. 前処理ディレクティブが実行され、マクロの呼び出しが拡張され、[...]

セクション6.10の前処理ディレクティブは次のように述べています。

プリプロセッシングディレクティブは、#プリプロセッシングトークンで始まる一連のプリプロセッシングトークンで構成されます(トランスレーションフェーズ4の開始時に)ソースファイルの最初の文字(オプションで改行文字を含まない空白の後ろ)または少なくとも1つの改行文字を含む空白に続き、次の改行文字で終了します。

唯一の可能性のある論争は、括弧内の式「(翻訳フェーズ4の開始時)」です。これは、フェーズ4の終わりまで、スペースで置き換えられないため、ハッシュの前のコメントは存在しない必要があることを意味します。

他の人が指摘したように、先行標準のCプリプロセッサはいくつかの方法で均一に動作せず、プリプロセッサディレクティブの前後のスペースは、その前にスペースがあるプリプロセッサディレクティブを認識しないなど、さまざまなコンパイラが異なる処理を行う領域の1つでした。 。

コメントが分析される前にバックスラッシュと改行の削除が行われることは注目に値します。したがって、//コメントをバックスラッシュで終了しないでください。


7

なぜそれほど一般的ではないのかわかりません。確かに、プリプロセッサディレクティブをインデントしたい場合があります。

私の邪魔をし続けている1つのこと(そして、ときどき私がやめることをやめるように説得すること)は、ほとんどまたはほとんどのエディター/ IDEが、わずかな挑発で列1にディレクティブをスローすることです。それは地獄として迷惑です。


5

最近では、これは主にスタイルの選択だと思います。私が考えます遠い過去のある時点で、すべてのコンパイラは、プリプロセッサの定義をインデントの概念をサポートしていません。私はいくつかの調査を行い、その主張をバックアップすることができませんでした。しかし、いずれにせよ、すべての最新のコンパイラはプリプロセッサマクロをインデントするという考えをサポートしているようです。CまたはC ++標準のコピーがないので、これが標準の動作であるかどうかはわかりません。

いいスタイルかどうか。個人的に、私はそれらをすべて左に保つ考えが好きです。それはあなたにそれらを探すための一貫した場所を与えます。ええ、非常に入れ子になったマクロがあると、煩わしくなります。しかし、それらをインデントすると、最終的にはさらに奇妙なコードになってしまいます。

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

14
このコードが奇妙に見える理由は、インデントの2つの「ストリーム」を作成したためです。4行目をさらに1レベルインデントし、6行目と7行目をさらに2レベルインデントします。
ケビンレイティ

3
完全に同意する。中括弧を付けることもあるので、#ifはifのように見えます。
baash05 2010年

3
私は、実際のコードがある部分に行が含まれない ようにコードを調整するために、一生懸命努力して#ifdefます。代わりに、条件付きのものが必要な場合は、分解された関数または分解されたマクロに入れます。私が見つけた方法の方がはるかに明確です(まあ、少なくとも私にとってはそうです)。理想的には、これらのすべての分解された部分は他のファイル(ヘッダーまたは条件付きでコンパイルされたソースファイル、通常の「条件」はコードがビルドされるプラットフォームです)にあります。
ドナルフェロー

2
4行目を1レベル、6行目と7行目を2レベルインデントします。
Rocketmagnet 2010

3

あなたが与えた例では、インデントを使用してそれをより明確にすることが適切であるかもしれません、ネストされたディレクティブのそのような複雑な構造があるのを見てください。

これらのディレクティブはコードの他の部分とは別に動作するため、個人的には、ほとんどの場合、インデントを付けないようにすると便利だと思います。#ifdefなどのディレクティブは、コンパイラがコードを認識する前にプリプロセッサによって処理されるため、#ifdefディレクティブの後のコードブロックはコンパイルされない場合もあります。

ディレクティブをコード内に散在させる場合、ディレクティブを視覚的に分離しておくことが重要です(例のように、ディレクティブの専用ブロックではありません)。


3
IPの観点から、コンパイルされていないものとjmpのために到達されないものの違いは何ですか。
baash05 2010年

2

私は現在、#defines、#ifdefs、#elses、#endifs、#etcなどの恐ろしい混合があるいくつかのコードで作業しています。これらすべては、通常のCコードと混在することがよくあります。#definesをインデントしないと、読みにくくなります。そして、インデントされたコードとインデントされていない#definesの混在は悪夢です。

一般的な解決策は、ディレクティブにコメントを付けることです。これにより、ディレクティブが何を参照しているかが簡単にわかります。

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

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

6
私はそのスタイルを見てきました、私の上司はそれを使用しています。そして、彼の他のコードのように、それは単に混乱を引き起こします。通常のif()ステートメントからすべてのインデントを削除し、代わりにそれらのコメントを使用することを想像してみてください。あなたは彼らが何を参照しているかを簡単に見ることができないと不満を言うでしょう。
Rocketmagnet 2010

2

現在利用可能なほとんどすべてのC / CPPコンパイラでは、制限はありません。コードをどのように配置するかは、ユーザー次第です。とても幸せなコーディング。


1
まともな答え。特定のスタイルガイドリファレンスを追加して改善できますか?
EtherDragon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.