#define vs const in Objective-C


81

私はObjective-Cconstを初めて使用しますが、前処理ディレクティブに関していくつか質問があり#defineます。

まず、を使用して定数の型を定義することはできないことがわかりました#define。何故ですか?

第二に、それらの1つを別のものよりも使用する利点はありますか?

最後に、どちらの方法がより効率的および/またはより安全ですか?

回答:


107

まず、#defineを使用して定数の型を定義することは不可能であることがわかりました。それはなぜですか?

なんで?それは真実ではない:

#define MY_INT_CONSTANT ((int) 12345)

第二に、それらの1つを別のものよりも使用する利点はありますか?

はい。 #defineコンパイルが開始される前でも置き換えられるマクロを定義します。 const変数を変更しようとするとコンパイラがエラーにフラグを立てるように、変数を変更するだけです。を使用できるが使用#defineできないコンテキストがありますconst(最新のclangを使用して1つを見つけるのに苦労していますが)。理論的には、constは実行可能ファイル内のスペースを占有し、メモリへの参照を必要としますが、実際にはこれは重要ではなく、コンパイラによって最適化される可能性があります。

constsは、sよりもはるかにコンパイラとデバッガに適しています#define。ほとんどの場合、これは、どちらを使用するかを決定するときに考慮する必要がある最も重要なポイントです。

使用できるが使用でき#defineないコンテキストについて考えただけですconst。たくさんの.cファイルで使用したい定数がある場合は、#defineそれをヘッダーに貼り付けるだけです。を使用するconstと、Cファイルに定義が必要です。

// in a C file
const int MY_INT_CONST = 12345;

// in a header
extern const int MY_INT_CONST;

ヘッダー内。 MY_INT_CONSTで定義されているものを除いて、Cファイルの静的またはグローバルスコープ配列のサイズとして使用することはできません。

ただし、整数定数の場合は、を使用できますenum。実際、それはAppleがほぼ常に行っていることです。これには、#definesとconstsの両方のすべての利点がありますが、整数定数に対してのみ機能します。

// In a header
enum
{
    MY_INT_CONST = 12345,
};

最後に、どちらの方法がより効率的および/またはより安全ですか?

#define理論的にはより効率的ですが、私が言ったように、最近のコンパイラはおそらくほとんど違いがないことを保証します。 #define割り当てようとすると常にコンパイラエラーになるという点で、より安全です。

#define FOO 5

// ....

FOO = 6;   // Always a syntax error

constコンパイラが警告を出す場合がありますが、sはだまされて割り当てられる可能性があります。

const int FOO = 5;

// ...

(int) FOO = 6;     // Can make this compile

プラットフォームによっては、定数が読み取り専用セグメントに配置され、C標準に従って公式に定義されていない動作である場合、実行時に割り当てが失敗する可能性があります。

個人的には、整数定数の場合、enum他のタイプの定数には常にsを使用しますが、そうしconstないという非常に正当な理由がない限り、使用します。


古いことは知っていますが、defineを使用できるconstを使用できないインスタンスの1つは、「NSNumber * const MY_NSNUM_CONSTANT = @ 5」を使用して実行できなかった「#defineMY_NSNUM_CONSTANT @ 5」です
shortstuffsushi

#defineはconstよりも実行可能ファイルでより多くのスペースを占めると私は主張します。constは1回格納されますが、これは単なるテキスト置換であるため、使用するたびに#defineが乗算されます。しかし、違いは取るに足らないので、私は不必要に衒学者です。
ライアンバランタイン2015

@RyanBallantyne文字列定数のようなものには正しいかもしれませんが、整数定数には適さないと思います。定数を1つの場所に格納する場合でも、それにアクセスするには、少なくとも。と同じ大きさのアドレスが必要intです。しかし、それが現代のコンパイラーでまったく違いを生んだとしたら、私は非常に驚きます。
JeremyP 2015

16

Cコーダーから:

Aconstは、内容を変更できない単なる変数です。

#define name valueただし、は、のすべてのインスタンスnamevalue。に置き換えるプリプロセッサコマンドです。

たとえば、の場合、コード内の#define defTest 5すべてのインスタンスはコンパイル時にdefTestに置き換えられ5ます。


11

同じことを意図していない#define命令とconst命令の違いを理解することが重要です。

const

constは、初期化されると一定になる、要求されたタイプからオブジェクトを生成するために使用されます。これは、プログラムメモリ内のオブジェクトであり、読み取り専用として使用できることを意味します。オブジェクトは、プログラムが起動されるたびに生成されます。

#define

#defineコードの可読性と将来の変更を容易にするために使用されます。定義を使用する場合は、名前の背後にある値のみをマスクします。したがって、長方形を操作する場合、対応する値を使用して幅と高さを定義できます。次に、コードでは、数字の代わりに名前があるため、読みやすくなります。

後で幅の値を変更することにした場合は、ファイル全体で退屈で危険な検索/置換を行う代わりに、定義で値を変更するだけで済みます。コンパイル時に、プリプロセッサは定義されたすべての名前をコード内の値に置き換えます。したがって、それらを使用して時間を無駄にすることはありません。


7

他の人々のコメントに加えて、使用中のエラー#defineは、プリプロセッサがコンパイラの前にそれらを取得するため、デバッグが難しいことで有名です。


3

プリプロセッサディレクティブは嫌われているので、を使用することをお勧めしますconst。プリプロセッサディレクティブはコンパイル前に解決されるため、プリプロセッサでタイプを指定することはできません。まあ、できますが、次のようなものです。

#define DEFINE_INT(name,value) const int name = value;

として使用します

DEFINE_INT(x,42) 

これはコンパイラによって次のように表示されます

const int x = 42;

まず、#defineを使用して定数の型を定義することは不可能であることがわかりました。それはなぜですか?

できます、私の最初のスニペットを見てください。

第二に、それらの1つを別のものよりも使用する利点はありますか?

一般に、constプリプロセッサディレクティブの代わりに持つことはデバッグに役立ちますが、この場合はそれほどではありません(ただし、それでもそうです)。

最後に、どちらの方法がより効率的および/またはより安全ですか?

どちらも同じくらい効率的です。マクロは実行時に変更できないため、より安全になる可能がありますが、変数は変更できます。


const ...マクロを使用する代わりに、単に入力するのはなぜですか?
エドヒール2012年

1
@EdHealはしません。「#defineを使用して定数の型を定義することは不可能であることがわかりました。それはなぜですか?」と答えることができると言っていました。
Luchian Grigore 2012

1
> pre-processor directives are frowned upon[要出典]
Ben Leggiero 2015年

次のようなタイプを使用できると思います:#define myValue((double)2)。私が理解しているように、プリプロセッサは「myValue」を、タイプ情報を含め、defineステートメントでその後に続くものに置き換えるだけです。
vomako 2015

1

私は以前に#defineを使用して、次のようなものがある場合のように、1つのメソッドからより多くのメソッドを作成できるようにしました。

 // This method takes up to 4 numbers, we don't care what the method does with these numbers.
 void doSomeCalculationWithMultipleNumbers:(NSNumber *)num1 Number2:(NSNumber *)num2 Number3:(NSNumber *)num23 Number3:(NSNumber *)num3;

しかし、私は3つの数値と2つの数値のみを受け取るメソッドも必要なので、2つの新しいメソッドを作成する代わりに、#defineを使用して同じメソッドを使用します。

 #define doCalculationWithFourNumbers(num1, num2, num3, num4) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), (num4))

 #define doCalculationWithThreeNumbers(num1, num2, num3) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), (num3), nil)

 #define doCalculationWithTwoNumbers(num1, num2) \
         doSomeCalculationWithMultipleNumbers((num1), (num2), nil, nil)

これはかなりクールなことだと思います。メソッドに直接移動して、不要なスペースにnilを入れるだけでよいのはわかっていますが、ライブラリを構築している場合は非常に便利です。また、これはどのように

     NSLocalizedString(<#key#>, <#comment#>)
     NSLocalizedStringFromTable(<#key#>, <#tbl#>, <#comment#>)
     NSLocalizedStringFromTableInBundle(<#key#>, <#tbl#>, <#bundle#>, <#comment#>)

行われます。

私はあなたが定数でこれを行うことができるとは思わないのに対して。ただし、定数は#defineに比べて利点があります。たとえば、#defineで型を指定できないのは、コンパイル前に解決されるプリプロセッサディレクティブであり、#defineでエラーが発生した場合、デバッグが困難になるためです。定数。どちらにも長所と短所がありますが、どちらを使用するかはプログラマーによって異なります。#defineを使用して表示したことを実行するライブラリと、型を指定する必要のある定数変数を宣言する定数の両方を使用してライブラリを作成しました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.