配列からptrへの自然な型の減衰を伴うCでの標準的な配列の使用法
@Bo Perssonは、ここで彼のすばらしい答えを正しく述べています。
配列をパラメータとして渡す場合、これは
void arraytest(int a[])
とまったく同じ意味
void arraytest(int *a)
ただし、上記の2つの形式も追加します。
とまったく同じ意味
void arraytest(int a[0])
これはまったく同じ意味です
void arraytest(int a[1])
これはまったく同じ意味です
void arraytest(int a[2])
これはまったく同じ意味です
void arraytest(int a[1000])
等
上記の配列例のすべてで、入力パラメーターの型はに減衰し、int *
ビルドオプション-Wall -Wextra -Werror
がオンになっている場合でも、警告やエラーなしで呼び出すことができます(これらの3つのビルドオプションの詳細については、こちらのリポジトリを参照してください)。この:
int array1[2];
int * array2 = array1;
arraytest(array1);
arraytest(array2);
実際のところ、「サイズ」の値([0]
、[1]
、[2]
、[1000]
配列パラメータの内部など)がここに美的/自己文書化のため、明らかばかりで、任意の正の整数を指定できます(size_t
あなたが欲しいと思うタイプ)!
ただし、実際には、これを使用して、関数が受け取ると予想される配列の最小サイズを指定する必要があります。これにより、コードを作成するときに、追跡と検証が簡単になります。MISRA-C-2012規格(ご購入/ここ£15.00のために、標準の236-PG 2012バージョンのPDFをダウンロードし、これまでの状態(強調追加)へと行きます):
規則17.5配列型を持つと宣言されたパラメータに対応する関数の引数は、適切な数の要素を持たなければならない。
..。
パラメータが指定されたサイズの配列として宣言されている場合、各関数呼び出しの対応する引数は、少なくとも配列と同じ数の要素を持つオブジェクトを指している必要があります。
..。
関数パラメーターに配列宣言子を使用すると、ポインターを使用するよりも明確に関数インターフェースを指定できます。関数が期待する要素の最小数は明示的に示されていますが、これはポインターでは不可能です。
言い換えれば、C標準では技術的に強制されていなくても、明示的なサイズ形式を使用することをお勧めします。少なくとも、開発者としてのあなたや、コードを使用している他の人にとって、関数が期待するサイズ配列を明確にするのに役立ちます。あなたが渡す。
Cの配列に型安全性を強制する
@Winger Sendonが私の回答の下のコメントで指摘しているように、Cに配列タイプを配列サイズに基づいて異なるものとして処理させることができます!
まず、あなたが使用して、その私の例では、単に上記認識する必要がありint array1[2];
、次のように:arraytest(array1);
原因array1
自動的に崩壊しますint *
。ただし、代わりにのアドレス を取得してarray1
呼び出すとarraytest(&array1)
、まったく異なる動作が発生します。今、それは崩壊しませんint *
!代わりに、の型は&array1
ですint (*)[2]
。これは、「intのサイズ2の配列へのポインタ」または「int型のサイズ2の配列へのポインタ」を意味します。したがって、次のように、Cに配列の型安全性をチェックさせることができます。
void arraytest(int (*a)[2])
{
}
この構文は読みにくいですが、関数ポインタの構文と似ています。オンラインツールcdeclは、「intの配列2へのポインタとしてaを宣言する」(2の配列へのポインタ)というint (*a)[2]
意味を示しています。:括弧なしのバージョンでこれを混同しないでください、意味:「int型へのポインタの配列2として宣言する」(2つの配列のポインタへ)。int
int * a[2]
int
さて、この関数&
は、入力パラメータとして正しいサイズの配列へのポインタを使用して、このようなアドレス演算子()で呼び出す必要があります!:
int array1[2];
arraytest(&array1);
ただし、これにより警告が生成されます。
int array1[2];
arraytest(array1);
あなたはあり、ここで、このコードをテストします。
Cコンパイラにこの警告をエラーに変換させ、常にarraytest(&array1);
正しいサイズとタイプ(int array1[2];
この場合)の入力配列のみを使用して呼び出す必要があるようにする-Werror
には、ビルドオプションに追加します。onlinegdb.comで上記のテストコードを実行する場合は、右上の歯車アイコンをクリックし、[追加のコンパイラフラグ]をクリックしてこのオプションを入力します。ここで、次の警告が表示されます。
main.c:34:15: warning: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Wincompatible-pointer-types]
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
このビルドエラーに変わります:
main.c: In function ‘main’:
main.c:34:15: error: passing argument 1 of ‘arraytest’ from incompatible pointer type [-Werror=incompatible-pointer-types]
arraytest(array1);
^~~~~~
main.c:24:6: note: expected ‘int (*)[2]’ but argument is of type ‘int *’
void arraytest(int (*a)[2])
^~~~~~~~~
cc1: all warnings being treated as errors
次のように、特定のサイズの配列への「タイプセーフ」ポインタを作成することもできることに注意してください。
int array[2];
int (*array_p)[2] = &array;
...しかし、これは必ずしもお勧めしません。言語構文の複雑さ、冗長性、コードの設計の難しさという非常に高いコストで、あらゆる場所で型の安全性を強制するために使用される多くのC ++の策略を思い出させてくれるので、私は嫌いです。これまでに何度も怒鳴りました(例:「C ++に関する私の考え」を参照)。
追加のテストと実験については、すぐ下のリンクも参照してください。
参考文献
上記のリンクを参照してください。また:
- オンラインでの私のコード実験:https://onlinegdb.com/B1RsrBDFD