36052


[このサイト](http://libjpeg.sourceforge.net)でダウンロードできる「[libjpeg](https://ja.wikipedia.org/wiki/Libjpeg)」のソースコードを見て、

> cjpegとdjpeg - JPEGと、他の一般的な画像フォーマットとの変換を行う。

と記述されていたので、`cjpeg.c`のソースを見ました。  
すると、1~22行あたりまでは利用の規約などが記載されており、24行目あたりからコードが書かれていると思います。

[code]

    #include "cdjpeg.h"     /* cjpeg / djpegアプリケーションの共通デッキ */
    #include "jversion.h"       /* for version message */
    
    #ifdef USE_CCOMMAND     /* Macintosh用のコマンドラインリーダー */
    # ifdef __MWERKS__
    #  include <SIOUX.h>              /* Metrowerksはこれを必要とします */
    #  include <console.h>      /* ... この */
    # endif
    # ifdef THINK_C
    #  include <console.h>      /* ここでそれを宣言してください */
    # endif
    #endif
    
[/code]

> 質問  
>  1\. `include "cdjpeg.h"` これは、`cdjpeg.h`のファイルを読み込んでという意味ですよね？  
>  2\. `#ifdef USE_CCOMMAND` は使い方を調べたんですが、#ifdef <識別子名> <処理>
> となっていて、<識別子名>が定義済みなら<処理>を実行するというコードですよね？  
>  `USE_CCOMMAND` は、読み込んだファイルで定義されている場合も実行するんですか？  
>  3\. `#include
> "cdjpeg.h"`先の`cdjpeg.h`で`cdjpeg.h`と定義されているんですが、`#define`って、`#define A
> B`という記述でコードのAをすべてBと置き換えて実行しなさいという意味ですよね？今回の場合、Bにあたる部分がないのですが、どういう解釈をすればよいですか？


CC BY-SA 3.0
2017-07-02T04:56:17.513
36025
2017-07-03T01:49:58.297
2017-07-02T08:20:22.657
4236
20192
question
c preprocessor
#ifdef USE_CCOMMANDという記述 libjpeg　のソースコード


質問への回答は以下になるでしょうか。

  1. はい。`#include "cdjpeg.h"は、ファイル`cdjpeg.h`を読み込む、の意味です。
  2. はい。マクロ変数(識別子)`USE_CCOMMAND`を定義しています。   
なお、マクロ変数はそれが参照される時点で定義されている必要があるので、読み込んだファイルで定義されている場合、参照前に読み込むよう記述する必要があります。

例

[code]     #include "macro.h" /* この中で #define A と記述されている */

    #ifdef A /* マクロ変数 A を参照するのは macro.h をインクルードした後である必要がある */
    (処理)
    #endif
    
[/code]

  3. `#define A`と記述した場合、`B`は「空」を指定したものと考えるとよいと思います。

例

[code]     #define A /* マクロ変数Aを空で定義 */

    printf(A "Hello, World\n"); /* printf("Hello, World\n"); と同じ */
    #define STR "Hey, " /* マクロ変数STRを"Hey, "で定義 */
    printf(STR "Hello, World\n"); /* printf("Hey, Hello, World\n"); と同じ */
    
[/code]

# 追記

内容が空で定義するマクロ変数を使う場合ですが、大きく分けて2種類あります。

1つは、内容は不要で定義の有無だけが必要な場合です。質問の例にもありますが、`#ifdef
USE_CCOMMAND`によるプリプロセスの分岐がそれにあたります。

もう一つは、`#ifdef`による分岐との組み合わせで、ログ出力等の実行文を生成しないようにする場合です。例えば、次のようなソースコードを書いた場合、マクロ変数`TRACE`を定義しないと、`LOG`部分が「空」に置換されて`func`関数内の`LOG`部分は何も実行文がなくなります。

[code]

    例
    
    #ifdef TRACE
    #define LOG printf("TRACE: %s:%d\n", __FILE__, __LINE__)
    #else
    #define LOG
    #endif
    
    void func()
    {
        LOG;
        /* 処理 */
        LOG;
    }
    
    このコードの前に`#define TRACE`がある場合に生成されるfunc関数の内容
    
    void func()
    {
        printf("TRACE: %s:%d\n", __FILE__, __LINE__);
        /* 処理 */
        printf("TRACE: %s:%d\n", __FILE__, __LINE__);
    }
    
    マクロ変数 TRACE が定義されていない場合に生成されるfunc関数の内容
    
    void func()
    {
    
        /* 処理 */
    
    }
    
[/code]


CC BY-SA 3.0
2017-07-02T07:55:25.377
36027
2017-07-02T12:33:30.890
2017-07-02T12:33:30.890
19110
20098
36025
answer


質問2の答えですが、マクロ変数や識別子はどこで宣言されても有効です。  
なので、ソースファイル中のどこにも無くても、コンパイル時のコマンドラインに `-D"XXX"`や
`-D"XXX=n"`と記述することでもマクロは定義出来ます。  
（その時は毎回`-D何々`とタイプするのは面倒なのでMakefileに記述するのでしょうね）  
`#ifdef XXX`は「XXXが定義されていたら、値が何であろうとも」と読み替えると理解しやすいかと思います。

質問3の答えですが、「マクロシンボルは定義するけど、値は何も定義しないよ」という言う意味になります。  
よくある使い方としては同じファイルが何度もインクルードされて  
内容を何度も定義することを防ぐために使います。  
例えば、foo.h, bar.h, baz.h という3つのヘッダーファイルがあったとして、

bar.h には

[code]

    #include "foo.h"
    
[/code]

baz.h には

[code]

    #include "foo.h"
    #include "bar.h"
    
[/code]

と書かれていたとしたら、baz.hを展開した時に

  1. 最初にfoo.hが読み込まれます
  2. 次にbar.hが読み込まれます
  3. bar.hの内容を展開するときに、`#include "foo.h"`と書かれているので、もう一回foo.hが読み込まれます

と言うようにfoo.hが２度読み込まれて、foo.hの内容が２度定義されてしまいます。

これを防ぐために

[code]

    #ifndef foo.h    // foo.h が一度も読み込まれていなかったら
    #define foo.h    // foo.h が読み込まれた印を残して
        // foor.hで定義したい内容
    #endif           // foo.h の内容終わり
    
[/code]

と記述することで、２度目にfoo.hが読み込まれても既にfoo.hは定義されているので、  
foo.hの本来定義したい内容を再展開しないように抑制することが出来ます。


CC BY-SA 3.0
2017-07-02T11:44:34.047
36035
2017-07-02T11:44:34.047
14745
36025
answer


大前提として、C言語及びC++言語ではソースコードをコンパイラー本体に渡す前にプリプロセッサで前処理します。質問の`#include`、`#ifdef`、`#define`等はプリプロセッサに対するコマンドであり、コンパイラー本体はこれらを参照しません。  
コンパイルオプション`-E`を使用するとプリプロセッサで処理されコンパイラー本体が参照する生のソースコードを得ることができます。参考までにプリプロセッサによってどのような処理が行われているのか確認することをお勧めします。

この点が理解できていると、疑問点も解消しやすいと思います。

>   1. `include "cdjpeg.h"` これは、`cdjpeg.h`のファイルを読み込んでという意味ですよね？
>

「読み込んで」の対象はコンパイラー本体ではなくプリプロセッサであることに注意してください。`#include
"cdjpeg.h"`はプリプロセッサに対して当該行部分に`cdjpeg.h`を読み込み展開することを指示します。コンパイラー本体は展開済みソースコードを参照することになります。

>   2. `#ifdef USE_CCOMMAND` は使い方を調べたんですが、#ifdef <識別子名> <処理>
> となっていて、<識別子名>が定義済みなら<処理>を実行するというコードですよね？  
>  `USE_CCOMMAND` は、読み込んだファイルで定義されている場合も実行するんですか？
>

「実行する」という解釈が理解を妨げています。  
状況によってコンパイラー本体に見せたいコードと見せたくないコードがあります。その際、プリプロセッサでコンパイラー本体に見せる／隠すを制御します。  
`#ifdef
USE_CCOMMAND`行時点で`USE_CCOMMAND`マクロが定義されている場合は`#endif`までのコードを見せます（つまりソースコードをそのまま残します）。逆に`USE_CCOMMAND`マクロが定義されていない場合は`#endif`までのコードを隠します（具体的には空行に置き換えます）。  
コンパイラー本体はプリプロセッサによって編集されたソースコードを参照します。

>   3. `#include
> "cdjpeg.h"`先の`cdjpeg.h`で`cdjpeg.h`と定義されているんですが、`#define`って、`#define A
> B`という記述でコードのAをすべてBと置き換えて実行しなさいという意味ですよね？今回の場合、Bにあたる部分がないのですが、どういう解釈をすればよいですか？
>

前半部分は意味不明です。後半部分も「実行しなさい」ではありません。  
プリプロセッサがソースコード中の`A`と書かれている部分を全て`B`に書き換えます。`B`にあたる部分がない場合はソースコード中の`A`と書かれている部分を全て消します。  
コンパイラー本体は書き換え後のソースコードを参照することになります。

* * *

以上は概念説明です。C言語登場当時は上記説明の通りに動作していましたが、現在はコンパイルの高速化のためコンパイラー本体がプリプロセッサの役割も兼ねていて、独立したプリプロセッサを呼び出さない場合もあります。しかし、それは実装の違いでしかなく、概念としては現在も変わりません。


CC BY-SA 3.0
2017-07-03T01:49:58.297
36052
2017-07-03T01:49:58.297
4236
36025
answer