2

構造内で VLA を宣言できるようにする、優れた GCC 拡張機能を使用しています。今のところ、この方法で VLA を関数に (値で) 渡す方法を見つけました。また、非常に限られたコンテキストで返す方法を見つけました。

この例の関数コードは次のとおりです。

extern void func3()
{
    size_t size;

    scanf("%zu", &size);

    struct tx{int _[size];} fn()
    {
        struct tx rt;

        for(size_t i=0; i < size; ++i)
            scanf("%d", &rt._[i]);

        return rt;
    }

    volatile __typeof__(fn) *pf = fn;
}

上記の例は、テスト目的で設計されています (特に、コンパイルされたバイナリ コードを比較するため)。

ただし、返される配列のサイズは関数の異なる呼び出し間で変化しないため、これはかなり制限されています。

返された配列のサイズを、関数パラメーターの 1 つまたはこの関数の他のローカルと等しくするにはどうすればよいでしょうか。

alloca割り当てられたメモリは関数終了 (IRC) ですぐに破棄されるため、この場合は役に立たないと思います。

私はこのようなものを書きたい:

/*???*/ func5()
{
    size_t size;

    scanf("%zu", &size);

    struct {int _[size];} rt;

    for(size_t i=0; i < size; ++i)
        scanf("%d", &rt._[i]);

    return rt; //ok - return the structure
}

言い換えれば、疑問符内の型は何でしょうか? または、他の解決策があるかもしれません(ただし、を使用せずにmalloc)?

このような関数の理論的な使用法では、返された構造体のサイズを呼び出し元が利用できないため、返された値を格納するために理論的には別の型が必要になります (これを回避する方法がない限り?)。しかし、一見すると、次のようになります

size_t size;

//scanf("%zu", &size);

struct {int _[size];} tmp; //create locally VM type 
                            //compatible with the one
                            //returned by our theoretical func5

                            //we can't directly initialize tmp here (gcc complains)


tmp = ((__typeof__(tmp) (*)())func5)(); //direct assignment between VM structures 
                                        //works here on the other hand

                                        //as function return value is rvalue and we can't
                                        //take its pointer and cast it to our local VM structure type
                                        //we instead cast the function pointer

このようなことをすると:

__typeof__(func5()) tmp = func5();

func5VM の戻り値の型は、その引数またはローカル変数に依存するため、機能しません。ただし、この関数はまだ定義できないため、現時点ではすべて理論上のものです。

4

3 に答える 3

2

[..] 呼び出された関数で VLA 割り当てを保持したい (および を使用せずにmalloc)。

C プログラム (一般的にホストされている実装) の動的メモリ ストレージのソースは、ヒープとスタックの 2 つだけです。

最初のものは使いたくありませんが、2 番目のものは自動的に管理されます。ある関数の「内部」に割り当てたものは、その関数が戻ったときに「消えて」しまいます。

唯一の例外は - もちろん - 戻り値です。ただし、スタックにとどまるために、そのメモリ (スタックを介して返される場合) が関数呼び出しのパラメーターの「下に割り当てられる」ため、これはあまり役に立ちません。したがって、関数を呼び出す前にそのサイズを知っておく必要があります (そうしないと、パラメーターや関数のローカル変数などを格納する場所がわかりません)。

「スタックへの割り当て」は本質的に「既知のバイト数だけポインターを進める」ことと同じであるため、ここに矛盾があります。関数内で割り当てたいが、関数に入る前にどれだけ割り当てるかを知る必要があります。

これはうまくいきません。

于 2016-03-04T23:44:01.840 に答える