4

次のコードを検討してください。

#include<stdio.h>

int main()
{
   char *ptr={'R','E','D','\0'};
   //char *ptr="RED";
}

次の警告のリストが表示されます。

warning: initialization makes pointer from integer without a cast|
warning: excess elements in scalar initializer|
warning: (near initialization for 'ptr')|

しかし、最初のステートメントをコメント アウトし、2 番目のステートメント (私のコードではコメント アウトされています) を有効にすると、正常に動作します。

なぜそうなのですか?2番目のケースと同じように、最初のケースでは同じ配列へのポインターが割り当てられないのはなぜですかptr?これの厳密な技術的理由は何ですか?

4

1 に答える 1

4

6.7.9 (11) [N1570 ドラフトの、C99 の 6.7.8 (11) と同一]​​ では、次のように指定されています。

スカラーの初期化子は、オプションで中括弧で囲まれた単一の式でなければなりません。オブジェクトの初期値は、(変換後の) 式の初期値です。単純な代入の場合と同じ型の制約と変換が適用され、スカラーの型が宣言された型の修飾されていないバージョンになります。

で複数の式を提供することにより、

char *ptr={'R','E','D','\0'};

「しなければならない」要件に違反しており、未定義の動作を呼び出しています (4 (2)):

制約またはランタイム制約の外側にある「しなければならない」または「してはならない」要件に違反した場合、動作は未定義です。

邪魔にならないように、この特定の種類の未定義の動作は、通常、コンパイラが最初の式を除くすべてを無視するため、主に発生します-

warning: excess elements in scalar initializer|

コードをあたかもそうであるかのように扱います

char *ptr = {'R'};

次に、当然のことながら、

warning: initialization makes pointer from integer without a cast|

'R'はポインタではなく整数であるためです。

一方で、

char *ptr = "RED";

配列(1) "RED"は、割り当ての場合と同様に、初期化時に初期要素へのポインターに変換されるため、まったく問題ありません。

(1)セクション 6.4.5 (6) で説明されているように、文字列リテラルはポインターではなく配列です。

変換フェーズ 7 では、値ゼロのバイトまたはコードが、文字列リテラルまたはリテラルから生じる各マルチバイト文字シーケンスに追加されます。次に、マルチバイト文字シーケンスを使用して、シーケンスを格納するのに十分な長さの静的ストレージ期間の配列を初期化します。文字列リテラルの場合、配列要素は char 型を持ち、マルチバイト文字シーケンスの個々のバイトで初期化されます。UTF-8 文字列リテラルの場合、配列要素は char 型を持ち、UTF-8 でエンコードされたマルチバイト文字シーケンスの文字で初期化されます。

(ワイド文字列リテラルは、 、またはのプレフィックスが付いているかどうかに応じてwchar_t[N]、 、char16_t[N]または型の配列です。)char32_t[N]LuU

于 2013-05-08T11:10:10.290 に答える