9

C で書かれた非常に単純なプログラム:

#include <stdio.h>
#include <stdlib.h>

void process(int array[static 5]){
    int i;
    for(i=0; i<5; i++)
        printf("%d ", array[i]);
    printf("\n");
}

int main(){

    process((int[]){1,2,3});
    process(NULL);

    return 0;
}

私はそれをコンパイルします:gcc -std=c99 -Wall -o demo demo.c

それコンパイルされ、実行するとクラッシュします(かなり予測可能です)。

なんで?static配列パラメーターのキーワードの目的は何ですか(この構造体の名前は何ですか?)?

4

2 に答える 2

15

配列内に適切な数 (例では 5) の要素のstatic最小値がある (したがって、配列ポインターがnull でもない)。また、未定義の動作を避けるために十分な大きさの配列を関数に渡さなければならないという、関数を使用するプログラマーへの指示でもあります。

ISO/IEC 9899:2011

§6.7.6.2 配列宣言子

制約
¶1 オプションの型修飾子とキーワードstaticに加えて、[and]は式 or を区切ることができ*ます。それらが式 (配列のサイズを指定する) を区切る場合、式は整数型を持つ必要があります。式が定数式の場合は、0 より大きい値を持つ必要があります。要素の型は、不完全型または関数型であってはなりません。オプションの型修飾子とキーワードstaticは、配列型を持つ関数パラメーターの宣言にのみ表示され、その後、最も外側の配列型の派生にのみ表示されます。

§6.7.6.3 関数宣言子 (プロトタイプを含む)

¶7 「型の配列」としてのパラメーターの宣言は、「型への修飾ポインター」に調整されるものとします。ここで、型修飾子 (存在する場合) は、配列型派生の[および内で指定されたものです。]キーワードが配列型派生のandstatic内にも現れる場合、関数の呼び出しごとに、対応する実引数の値は、サイズで指定された要素と少なくとも同じ数の要素を持つ配列の最初の要素へのアクセスを提供します。表現。[]


配列を期待する関数に null ポインターを渡すと (5 つの要素の配列の先頭であることが保証されます)、コードがクラッシュします。未定義の動作を呼び出しており、クラッシュは間違いに対処するための非常に賢明な方法です。

5 つの整数の配列が保証されている関数に 3 つの整数の配列を渡す場合は、より微妙です。繰り返しになりますが、未定義の動作を呼び出すと、結果は予測できなくなります。クラッシュが発生する可能性は比較的低いです。誤った結果が生じる可能性が非常に高くなります。

実際、staticこのコンテキストの には 2 つの別個のジョブがあり、2 つの別個のコントラクトを定義します。

  1. 関数のユーザーに、少なくとも 5 つの要素の配列を提供する必要があることを伝えます (そうしないと、未定義の動作が呼び出されます)。
  2. これは、オプティマイザーに、少なくとも 5 つの要素の配列への非 null ポインターを想定し、それに応じて最適化できることを伝えます。

関数のユーザーが関数の要件に違反した場合、すべての地獄が解き放たれる可能性があります (「鼻の悪魔」など。一般的に未定義の動作)。

于 2013-08-21T16:04:58.143 に答える
1

あなたのコードは正しいです(実際に推奨されています... C99、N1124/1256、6.7.5.3-7節を参照してください(以下のJonathanの全文を参照):

キーワード static が配列型派生の [ および ] 内にも現れる場合、関数の呼び出しごとに、対応する実引数の値は、少なくとも指定された数の要素を持つ配列の最初の要素へのアクセスを提供するものとします。サイズ表記にて。

エラーは、配列定義です。3 つの要素を保持するように配列を割り当てますが、5 つの要素を必要とする関数を ( 経由で[static 5]) 呼び出すと、クラッシュが発生します。

于 2013-08-21T16:10:58.270 に答える