ファイルスコープで可変的に変更された配列


87

「.m」ファイルの最上位にある次のようなものに似た、Objective-C実装ファイル全体で使用される定数静的配列を作成したいと思います。

static const int NUM_TYPES = 4;
static int types[NUM_TYPES] = { 
  1,
  2, 
  3, 
  4 };

NUM_TYPES後でファイルで使用する予定なので、変数に入れたいと思いました。

ただし、これを行うと、エラーが発生します

「ファイルスコープでさまざまに変更された「タイプ」」

これは、配列サイズが変数であることに関係している可能性があることを私は収集します(のように、整数リテラルをそこに置いても、このメッセージは表示されませんstatic int types[4])。

私はこれを修正したいのですが、多分私はそれをすべて間違って行っています...私はここに2つの目標があります:

  1. ファイル全体からアクセスできる配列を作成する
  2. NUM_TYPESファイル内のさまざまな場所に同じリテラルが散在しないように、変数にカプセル化する

助言がありますか?

[編集]これはCのFAQで見つかりました:http//c-faq.com/ansi/constasconst.html


2
代わりに定義としてそれを行うとどうなりますか?#define kNUM_TYPES 4
ホルヘイスラエルペーニャ

それはうまくいきます...どこかでそれを読んだことを覚えていると思ったので、何らかの理由でプリプロセッサを使用しないようにしようとしましたが、私はさらに調査を行っただけで、この場合はプリプロセッサを使用しない正当な理由を見つけることができませんでした。プリプロセッサでオブジェクトを作成している場合(のように@"An NSString literal")、あまり望ましくないかもしれません。コードの唯一の問題は、セミコロンが必要ないことです。
サム

ああ、そうだ、頭を上げてくれてありがとう、そして私が助けてくれてうれしい。
ホルヘイスラエルペーニャ

回答:


63

この警告の理由は、cのconstが定数を意味しないためです。「読み取り専用」を意味します。 したがって、値はメモリアドレスに格納され、マシンコードによって変更される可能性があります。


3
定義されたオブジェクトの変更constconstポインターからのキャストや値の格納など)は、未定義の動作です。したがって、このようなオブジェクトの値は、コンパイル時または実行時の定数です(ストレージ期間によって異なります)。C標準では使用できるとは言われていないため、この値を定数式で使用することはできません。(const宛先オブジェクトがconst動的に割り当てられていない、または割り当てられていない場合は、キャストして値を格納できます。文字列リテラルはconst書き込まれませんが、書き込まれることはありません。)
jilles 2012

3
@jillesは、「マシンコードによって変更される可能性がある」という意味ではなく、この回答の作成者が「Cコードによって変更される可能性がある」という意味ではありません。さらに、これには別の非常に正当な理由がありますextern。現在のTUをコンパイルするときに値が不明な定数が異なるTUに存在する可能性があります。

15
この答えを改善する方法は、この問題を解決する方法を示すことです。
ジョージストッカー2016年

33

とにかくプリプロセッサを使用する場合は、他の回答のように、コンパイラにNUM_TYPES自動的にの値を決定させることができます。

#define NUM_TYPES (sizeof types / sizeof types[0])
static int types[] = { 
  1,
  2, 
  3, 
  4 };

うわー、それは本当にクールです...私はそれが可能だとは知りませんでした。この計算のコストはごくわずかだと思います。また、コンパイラーがこれを静的な値に最適化できると思いますか?
サム

2
はい、そのsizeofようなオブジェクトの結果はコンパイル時定数です。
caf


11

列挙を使用することも可能です。

typedef enum {
    typeNo1 = 1,
    typeNo2,
    typeNo3,
    typeNo4,
    NumOfTypes = typeNo4
}  TypeOfSomething;

4

他の回答ですでに説明されているようにconst、Cでは、変数が読み取り専用であることを意味します。それはまだ実行時の値です。ただし、enumCでは実定数としてを使用できます。

enum { NUM_TYPES = 4 };
static int types[NUM_TYPES] = { 
  1, 2, 3, 4
};

3

私見これは多くのcコンパイラの欠陥です。私が使用したコンパイラは、アドレスに「静的const」変数を格納せず、コード内の使用を非常に定数に置き換えていることを知っています。これは、プリプロセッサの#defineディレクティブを使用する場合と、静的const変数を使用する場合に、生成されたコードに対して同じチェックサムを取得するため、確認できます。

どちらの方法でも、静的constはタイプセーフであるため、可能な限り#definesの代わりにstaticconst変数を使用する必要があります。


static const変数のアドレスを取ることができるので、それはかなり悪いように聞こえます。あなたが説明している振る舞いは有効な最適化かもしれませんが、それは確かに常に機能するものではありません。
2016年

実は大丈夫です。Cコンパイラは、可能な限り、constグローバル変数の個々の使用を定数値に置き換えてもかまいません。変数へのすべての参照が定数に変換される場合、コンパイラーはそれを完全に削除できます。どこかでアドレスを使用しても、削除されません。言語標準によれば、Cは、変数がconstであるかどうかに関係なく、サイズとして変数を持つグローバル配列を許可しないことを変更しません。
エヴァン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.