8

以下は、「文字列」をコンパイルして出力として出力します。

#include <stdio.h>

struct S { int x; char c[7]; };

struct S bar() {
    struct S s = {42, "string"};
    return s;
}

int main()
{
    printf("%s", bar().c);
}

どうやらこれはによると未定義の動作を呼び出すようです

C99 6.5.2.2 / 5関数呼び出しの結果を変更しようとした場合、または次のシーケンスポイントの後でそれにアクセスしようとした場合、動作は定義されていません。

「次のシーケンスポイント」についてどこに書かれているのかわかりません。何が起きてる?

4

3 に答える 3

10

あなたは言語の微妙なコーナーに出くわしました。

配列型の式は、ほとんどのコンテキストで、配列オブジェクトの最初の要素へのポインターに暗黙的に変換されます。ここでは適用されない例外は次のとおりです。

  • &配列式が単項演算子 (配列全体のアドレスを生成する)のオペランドである場合。
  • sizeof 単項or (C11 以降)_Alignof演算子のオペランドの場合 (sizeof arrは、ポインターのサイズではなく、配列のサイズを返します); と
  • 配列オブジェクトの初期化に使用される初期化子の文字列リテラルの場合 (に変換されchar str[6] = "hello";ません。)"hello"char*

( N1570ドラフトでは、例外のリストに誤って追加_Alignofされています。実際、理由は不明ですが_Alignof、式ではなく型名にのみ適用できます。)

暗黙の仮定があることに注意してください: 配列式は最初に配列オブジェクトを参照するということです。ほとんどの場合、そうです (最も単純なケースは、配列式が宣言された配列オブジェクトの名前である場合です)。ただし、この 1 つのケースで は、配列オブジェクトはありません

関数が構造体を返す場合、構造体の結果はvalue によって返されます。この場合、構造体には配列が含まれており、少なくとも論理的には、対応する配列オブジェクトのない配列値が返されます。したがって、配列式は、存在しない配列オブジェクトの最初の要素へのポインターに減衰します。bar().c

2011 ISO C 標準では、「一時的な有効期間」を導入することでこれに対処しています。これは、「構造体または共用体に配列型のメンバーが含まれる、構造体または共用体型の非左辺値式」にのみ適用されます ( N1570 6.2.4p8)。このようなオブジェクトは変更できず、その存続期間は、それを含む完全な式または完全な宣言子の最後で終了します。

したがって、C2011 の時点で、プログラムの動作は明確に定義されています。このprintf呼び出しは、一時的な有効期間を持つ構造体オブジェクトの一部である配列の最初の要素へのポインターを取得します。printfそのオブジェクトは、呼び出しが終了するまで存在し続けます。

しかし、C99 の時点では、動作は未定義です。引用した句が原因であるとは限りません (私が知る限り、介在するシーケンス ポイントはありません)。C99 では、必要な配列オブジェクトが定義されていないためです。働くことprintf

失敗する理由を理解するのではなく、このプログラムを機能させることが目標である場合は、関数呼び出しの結果を明示的なオブジェクトに格納できます。

const struct s result = bar();
printf("%s", result.c);

これで、一時的な保存期間ではなく自動保存期間を持つ構造体オブジェクトができたので、呼び出しの実行中および実行後に存在します。printf

于 2012-12-07T02:03:22.187 に答える
5

シーケンス ポイントは、完全な式の最後、つまりprintfこの例では return のときに発生します。シーケンスポイントが発生する他のケースがあります

事実上、このルールは、一時関数が次のシーケンス ポイントを超えて存続しないことを示しています。この場合、それは使用後かなり後に発生するため、プログラムの動作は非常に明確に定義されています。

明確に定義されていない動作の簡単な例を次に示します。

char* c = bar().c; *c = 5; // UB

ここでは、 が作成された後にシーケンス ポイントが満たさcれ、それが指すメモリが破棄されますがc、次に にアクセスしようとすると UB になります。

于 2012-12-07T01:50:23.503 に答える