web-dev-qa-db-ja.com

Objective-Cの#define vs const

Objective-Cを初めて使用しますが、constとプリプロセスディレクティブ#defineに関していくつか質問があります。

最初に、#defineを使用して定数の型を定義することは不可能であることがわかりました。何故ですか?

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

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

81
ObjectiveCoder

最初に、#defineを使用して定数の型を定義できないことがわかりましたが、それはなぜですか?

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

#define MY_INT_CONSTANT ((int) 12345)

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

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

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

#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

constsをだまして割り当てを行うことができますが、コンパイラは警告を発行する場合があります。

const int FOO = 5;

// ...

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

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

個人的には、整数定数には、他の型の定数には常にenumsを使用します。そうしない理由がない限り、constを使用します。

106
JeremyP

Cコーダーから:

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

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

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

16
MegaNairda

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

const

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

#define

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

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

10
fBourgeois

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

7
Ed Heal

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

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

そして、それを

DEFINE_INT(x,42) 

コンパイラからは次のように見えます

const int x = 42;

最初に、#defineを使用して定数の型を定義できないことがわかりました。なぜですか?

あなたは私の最初のスニペットを見ることができます。

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

一般に、プリプロセッサディレクティブの代わりにconstを使用すると、デバッグに役立ちますが、この場合はそれほどではありません(ただし、引き続き機能します)。

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

両方とも効率的です。マクロは潜在的に実行時に変更できないため、変数は可能ですが、より安全にできると思います。

2
Luchian Grigore

以前に#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を使用して表示したことを行うライブラリと、型を指定する必要のある定数変数を宣言する定数の両方を使用してライブラリを作成しました。

1
Popeye