5

私は最近、Cで複合リテラル配列への参照を実際に使用できることを知りました。これは便利だと思いますが、それがどのように機能するかはよくわかりません。

たとえば、次のように、戻り名の長さを気にしないソケットインターフェイス関数を呼び出すために変数を宣言する必要がないように、この機能を使用するとします。

int sockfamily(int fd)
{
    struct sockaddr_storage ss;

    getpeername(fd, (struct sockaddr *)&ss, (socklen_t [1]){sizeof(ss)});
    return(ss.ss_family);
} 

明らかsizeof(ss)に、スタックへのポインタをに渡すには、実際にスタックに格納する必要がgetpeernameあります。したがって、スタック上のスペースは、その目的のために割り当てて予約する必要がありますが、この割り当ての存続期間はどのくらいですか?割り当てられたままであるとどのくらい信頼できますか?

GCCのアセンブリ出力を見ると、呼び出しをgetpeernameループに入れた場合、割り当てはループの複数の反復で存続しないことがわかりますが、他のどのような条件でそれが存在しなくなる可能性がありますか?

4

1 に答える 1

12

関数内で定義された複合リテラルには、それを含むブロックに関連付けられた自動有効期間があります(つまり、同じレベルで宣言された変数と同じ有効期間)。これは、標準のパラグラフ6.5.2.5p5で指定されています。

int f() {
    for (int i = 0; i < 10; ++i) {
        int *j = (int []){i};  // storage duration of loop body
    }
} 

これは基本的に、複合リテラルが同じスコープで宣言および初期化された変数と同等であることを意味します。

int f() {
    for (int i = 0; i < 10; ++i) {
        int __unnamed[] = {i};
        int *j = __unnamed;
    }
} 

ポインタが存続する可能性のある場所に複合リテラルを渡す場合は注意してください。

int f() {
    int *p;
    if (1) {
        p = (int []){0, 1, 2};
        assert(p[0] == 0);
    }
    // *p is undefined
}
于 2013-02-19T10:37:28.283 に答える