18

int であるパラメーターに応じてサイズで配列が宣言される単純な関数があります。

    void f(int n){
        char a[n];
    };

    int main() {
        return 0;
    }

このコードはGNU C++ では正常にコンパイルされますが、MSVC 2005 ではコンパイルされません。

次のコンパイル エラーが発生します。

    .\main.cpp(4) : error C2057: expected constant expression
    .\main.cpp(4) : error C2466: cannot allocate an array of constant size 0
    .\main.cpp(4) : error C2133: 'a' : unknown size

これを修正するにはどうすればよいですか?

(新規/削除を使用せずに、MSVCでこれを機能させることに興味があります)

4

7 に答える 7

28

これは、C++ 言語に対する Gnu コンパイラの拡張機能の 1 つです。この場合、Visual C++ は完全に正しいです。C++ の配列は、コンパイル時の定数式であるサイズで定義する必要があります。

1999 年の C 言語への更新で、可変長配列と呼ばれる機能が C に追加されましたが、これは合法です。C99 をサポートする C コンパイラを見つけることができたとしても、これは簡単なことではありません。ただし、この機能は標準 C++ の一部ではなく、C++ 標準の次の更新で追加される予定でもありません。

C++ には 2 つの解決策があります。1 つ目は std::vector を使用する方法で、2 つ目は単に operator を使用する方法new []です。

char *a = new char [n];

私が回答を書いている間に、別の人が _alloca の使用を提案しました。私はそれに対して強くお勧めします。コンパイラ固有のように、非標準で移植性のないメソッドを別のメソッドと交換するだけです。

于 2008-11-23T04:44:01.930 に答える
10

スタックから割り当てる方法は g++ 拡張です。MSVC で同等のことを行うには、_alloca を使用する必要があります。

char *a = (char *)_alloca(n);
于 2008-11-23T04:40:29.380 に答える
5

標準ではないものを使用しています。実際には標準 C ですが、C++ ではありません。それはなんと奇妙でしょうか。

もう少し説明すると、ランタイム サイズのスタック配列は C++ の一部ではなく、C の最新の標準である C99 の一部です。コンパイラの互換性の問題を避けるために、使用を控えることをお勧めします。

機能の代替実装は、strager によって投稿されたように、new と delete を使用することです。

于 2008-11-23T04:47:55.747 に答える
2

可変長配列は C99 で導入されました。gcc ではサポートされていますが、msvc ではサポートされていません。MSVC チームの関係者によると、Microsoft は c/C++ コンパイラでこの機能をサポートする予定はありません。彼は、そのような場合に std::vector を使用することを提案しました。

C99 では、配列がスタックに割り当てられている必要がないことに注意してください。コンパイラはそれをヒープに割り当てることができます。ただし、gcc は配列をスタックに割り当てます。

于 2010-01-07T02:42:32.577 に答える
2

new/delete を使用して、ヒープ上のメモリを割り当て/解放できます。これは char[n] を使用するよりも遅く、エラーが発生しやすい可能性がありますが、残念ながらまだ C++ 標準には含まれていません。

new[] を使用するための例外セーフ メソッドとして、boost のスコープ付き配列クラスを使用できます。delete[] は、スコープ外に出ると自動的に呼び出されます

void f(int n) {
    boost::scoped_array<char> a(new char[n]);

    /* Code here. */
}

std::vector と reserve() 一部のバイトを使用することもできます。

void f(int n) {
    std::vector<char> a;
    a.resize(n);

    /* Code here. */
}

char[n] を使用したい場合は、C++ コードではなく C99 コードとしてコンパイルしてください。

何らかの理由でどうしてもデータをスタックに割り当てる必要がある場合は、MSVC ライブラリなどで提供される拡張機能である _alloca または _malloca/_freea を使用します。

于 2008-11-23T04:40:53.437 に答える
1

vector<>配列ではなくを使用するのが合理的でしょうか?または、を置き換えているchar *ので、std::string?これらはランタイムサイジングでうまく機能しますが、使用しない理由は他にもあるかもしれません。

于 2010-01-06T22:20:37.673 に答える
1

通常、C(他の人が指摘しているC99コンパイラを除く)およびC ++では、スタックにメモリを割り当てる場合、割り当てるもののサイズをコンパイル時に知る必要があります。ローカル変数はスタックに割り当てられるため、実行時に長さが関数パラメーターに依存する配列は、この規則に違反します。Kleinは、「new」演算子を使用することがこの問題を解決する1つの方法であると指摘するのは正しいです。


char *a = new char [n];

'a'はスタックに割り当てられたローカル変数ですが、配列全体(可変長)ではなく、配列(常に同じサイズであるため、コンパイル時に認識されます)へのポインターにすぎません。配列はヒープに割り当てられます。ヒープは通常、スタックの対応物を再生します。スタックはコンパイル時にサイズがわかっているもの用であり、ヒープはコンパイル時にサイズがわからないもの用です。

于 2008-12-31T15:41:41.177 に答える