先日、指定されたイニシャライザを少しいじってみたところ、驚いたことに、同じインデックスを複数回使用することが有効であることに気付きました。さらに、コンパイラの警告、エラー、さらには情報ステートメントさえ生成しませんでした。PC-Lint でさえ気にしていないようでした (これが一番驚いたと思います)。
この場合、コンパイラが情報メッセージを提供しない理由があるのか 、それとも追加のコンパイラ/リント/などがあるのか 疑問に思っています。これをキャッチまたはフラグするために使用できるオプション。
使用ツール: Renesas RX Standard Toolchain v1.2.0.0 (C99)、gcc バージョン 4.4.3 (Ubuntu 4.4.3-4ubuntu5.1) (VM 内)、Lint-NT 9.00i
たとえば、私が取り組んでいるいくつかの古いコードは、一連のコマンドを #defines し、コマンド構造の配列 (ここでは大幅に簡略化) を作成して、その特定のコマンドを見つけて使用するために循環します。
#define CMD_RMEM 0
#define CMD_WMEM 1
#define CMD_XCRC 2
#define CMD_NULL 3
typedef struct
{
const char cmdID;
const char* cmdStr;
} CMD;
const CMD commands[] = {
{CMD_RMEM,"RMEM"},
{CMD_WMEM,"WMEM"},
{CMD_XCRC,"XCRC"},
{CMD_NULL,"NULL"},
};
次に、どこかで見た指定された初期化子の構文を思い出し、重複したコマンド インデックスを検出することに加えて、配列内の項目の配置をより柔軟にできると考えました。
//(same #def's & typedef as above)
const CMD commands[] = {
[CMD_RMEM] = {CMD_RMEM,"RMEM"},
[CMD_NULL] = {CMD_NULL,"NULL"}, //different order in ititializer list,
// but designation keeps it in the same array/memory position, so
// this will still be the 'last' element
[CMD_CMEM] = {CMD_CMEM,"CMEM"},
[CMD_WMEM] = {CMD_WMEM,"WMEM"},
[CMD_XCRC] = {CMD_XCRC,"XCRC"},
};
上記の最初のコードと同じ効果が得られますが、配列宣言内の項目を柔軟に配置できます (そうです)。
#define CMD_RMEM 0
#define CMD_WMEM 1
#define CMD_XCRC 1 // obvious dupe in a short list, but not so obvious
// if part of a much longer list or if split among multiple files
#define CMD_NULL 2
// (Same designated initializer section as above)
同じ指定されたインデックスを複数回使用しているため、少なくとも警告が生成されます (そうではありません) (この例は、最後の NULL プレースホルダーをシフトせずにコマンドを追加すると簡単に発生する可能性があります)。
GCC Designated Initsページには、イニシャライザで範囲を使用できるようにする GNU 拡張機能が記載されています。これは、範囲全体を定義してから特定の部分をオーバーライドする機能で役立つことがわかります (たとえば、int arr[] = {[0 ... 99] = -1, [42] = 1}
なぜそれがまだなのかわかりません少なくともあるレベルではフラグが立てられていません...
同じ GCC ページのさらに下では、複数のフィールドのトピックに対処していますが、そのように動作する理由については説明していません。このようなオーバーライドされた初期化には副作用があり、副作用が発生するかどうかは不明です。現在、GCC はそれらを破棄し、警告を発行します。」
This IBM pageも興味深い例を示していますが、それでも(少なくとも私にとっては)なぜそれが少なくともある種のビルドメッセージではないのかについては答えていません...
最後に、この2000 年 12 月のgcc パッチ ページでは、重複したチェックが明示的に削除されたことを示していますが、(私が簡単に読んだ内容から) 理由を説明していません。
では、なぜこれが (一見) 見過ごされているのでしょうか? そして、コンパイラ(またはリント)にこれにフラグを付ける方法はありますか(安全性を高めるために)(c/c99では、「c ++を使用する」などとだけ言わないでください:p)?