3

引数を受け取る関数がありchar *ます:

Foo::Foo (char * arg0) {
    ....
}

元の例では、char[]この値を渡すために a が使用されています...

char bar[] = "Bar";
Instance.foo (bar);

...うまくいきます。

char *しかし、コンパイラからの警告なしに、文字列リテラルを としてキャストして渡すことができることがわかりました。

Instance.Foo ((char *) "Bar");

しかし、私の読書から、それは避けるべきであるようです - 指しているメモリの値は変わる可能性があります。

上記のステートメントは正しいですか (「これは避けるべきです」)、またはこの状況でこれは適切ですか?


編集 - さらなる調査により、私の質問にかなりうまく対処するこの記事が見つかりました...

4

2 に答える 2

10

はい、それは避けてください。これで、関数が を受け取ったconst char *場合、文字列リテラルで呼び出しても問題はありません。

C++ コンパイラはchar *、下位互換性の理由でのみ文字列リテラルをサポートしており、文字列リテラルに書き込むと、未定義の動作が発生します。

あなたがそうするとき、あなたがしているとき(あなたが変更できない4バイト文字列への非ポインタを作成しているところ)よりも根本的に異なることをしている(つまり、自由に変更できるchar bar[] = "Bar";値で4文字の配列を初期化する) )。{'B', 'a', 'r', '\0'}char bar* = "Bar";const

私の意見では、文字列リテラルを直接 に変換するべきではありませんchar*。代わりにconst char*(レガシー API と通信している場合) に明示的const_cast<char*>に入れconstて、保証のあるレガシー API と話しているというコメントを付けてください。 sを変更しないでくださいchar。これの利点は、API がアップグレードされたときにそれらの をプログラムで検索できることconst_cast、または への書き込みに関連するセグメンテーション違反がどこchar*から来たのかを見つけたいことです。

レガシー API をその内部const char*で実行するバージョンでラップすることもできconst_castます。

絶対に最悪の状況は、たくさんのchar*s がぶらぶらしていて、そのうちのいくつかは書き込み可能で、他は文字列リテラルからのものです。

于 2012-10-31T01:10:08.597 に答える
1

これは、ほとんどすべての犠牲を払って回避する必要があり、壊れたレガシー API とやり取りする必要がある場合にのみ実行し、ソース コードを見て、それらが文字列に書き込まれていないことを確認した場合にのみ実行してください。

万全を期して、strcpy渡す前に文字列をコピーしてください。

悪とは一体何なのか?文字列リテラルへの書き込みは未定義の動作です。

于 2012-10-31T01:08:53.973 に答える