12

C++を変換する方法std::stringやC 関数に渡す方法について質問する多くの投稿を読みましたが、これを行うことに関してかなりの注意事項があるようです。文字列が連続していることや、他の多くのことに注意する必要があります。要点は、注意すべきすべての点とその理由を私が本当に理解したことがないということです。const std::string&char*

C関数に渡すために必要なa から astd::stringへの変換を行うことについて、誰かが警告と失敗を要約できるかどうか疑問に思いましたか?char*

これstd::stringは、 がconst参照であり、単なる非 const 参照である場合、および C 関数が を変更するchar*場合と変更しない場合です。

4

5 に答える 5

11

まず、constreferenceまたはvalueが何も変更しないかどうか。

次に、関数が何を期待しているかを考慮する必要があります。関数がachar*または--で実行できるさまざまなことがあります。たとえば、char const*の元のバージョンではこれらの型が使用されていましたが、そのようなコードがまだ存在している可能性があります。うまくいけば、それはまれであり、以下では、C関数のが 終了した文字列を参照しmemcpyていると仮定します。char*'\0'

C関数がをとる場合、あなたはそれに;char const*の結果を渡すことができます。std::string::c_str()かかる場合はchar*、状況によって異なります。それがCの前日char*からのものであるという理由だけでconst、実際には何も変更しない場合は、 std::string::c_str()その後にaを付けるのconst_castが適切です。ただし、 C関数がchar*outパラメータとして使用している場合は、事態はさらに困難になります。私は個人的にバッファを宣言し、char[]これを渡してから結果をに変換することを好みますstd::stringが、すべての既知の実装でstd::stringは連続したバッファを使用し、標準の次のバージョンではそれが必要になるため、std::string最初のバッファを正しくディメンション化します(を使用して std::string::resize()から、を渡し&s[0]、その後、文字列を結果の長さに再ディメンション化します(strlen(s.c_str())、必要に応じて)も使用できます。

最後に(ただし、これはを使用するCプログラムの問題でもあり char[]ます)、生涯の問題を考慮する必要があります。ほとんどの関数はポインタを取得するchar*char const*単に使用し、それを忘れますが、関数がポインタをどこかに保存する場合、後で使用するために、文字列オブジェクトは少なくとも同じ長さで存続する必要があり、その期間中にそのサイズを変更しないでください。(繰り返しますが、そのような場合、私はを使用することを好みchar[]ます。)

于 2011-04-12T08:59:24.593 に答える
6

基本的に、重要なポイントは次の 3 つです。

  • 現在の標準によると、std::string連続したストレージを使用することは実際には保証されていません (私が知る限り、これは変更によるものです)。しかし実際には、現在のすべての実装はおそらく連続したストレージを使用しています。そのため、c_str()(and data()) は実際に文字列のコピーを内部的に作成する可能性があります …</p>

  • c_str()(and )によって返されるポインターはdata()、元の文字列に対して非 const メソッドが呼び出されない限り有効です。これにより、C 関数がポインターにハングアップしている場合 (実際の関数呼び出し中にのみ使用するのとは対照的に)、その使用は不適切になります。

  • 文字列が変更される可能性が少しでもある場合、constness を からキャストするのは得策でc_str()はありません。文字列のコピーを含むバッファーを作成し、それを C 関数に渡す必要があります。バッファを作成する場合は、null 終端を追加することを忘れないでください。

于 2011-04-12T08:53:24.110 に答える
4

[コメントを追加しますが、そのための十分な担当者がいないため、(まだ)別の回答を追加して申し訳ありません。]

現在の標準が std::string の内部バッファーが連続していることを保証していないことは事実ですが、実質的にすべての実装が連続バッファーを使用しているようです。さらに、新しい C++0x 標準 (ISO によって承認されようとしている) では、std::string に連続した内部バッファーが必要であり、現在の C++03 標準でさえ、data() またはを呼び出したときに連続したバッファーを返す必要があります。 &str[0] (ただし、必ずしも null で終わるわけではありません)。詳しくはこちらをご覧ください。

ただし、標準では、data()、c_str()、または演算子を呼び出したときに実装が実際に内部バッファーを返すことを強制しておらず、最適化の使用も妨げられていないため、文字列への書き込みは安全ではありません。コピー オン ライトのように、さらに複雑になる可能性があります (ただし、新しい C++0x ではコピー オン ライトが禁止されるようです)。そうは言っても、最大の移植性を気にしない場合は、ターゲットの実装をチェックして、内部で実際に何をするかを確認できます。私の知る限り、Visual C++ 2008/2010 は常に実際の内部バッファー ポインターを返し、コピー オン ライトを行いません (小さな文字列の最適化はありますが、おそらく問題にはなりません)。

于 2011-04-12T09:41:14.910 に答える
2

C 関数がの後ろの文字列を変更しない場合は、const インスタンスと非 const インスタンスの両方char*に を使用できます。理想的には ですが、そうでない場合 (レガシー API のため) を合法的に使用できます。ただし、文字列を変更しない限り、ポインターのみを使用できます。std::string::c_str()std::stringconst char*const_castc_str()

C 関数が の後ろの文字列を変更する場合、char*を使用する唯一の安全で移植可能な方法std::stringは、それを自分で (たとえば からc_str()) 一時バッファにコピーすることです! 後で一時メモリを解放してください。またはstd::vector、連続したメモリを持つことが保証されている を使用してください。

于 2011-04-12T08:52:26.827 に答える
1
  1. std:string はゼロバイトを格納できます。これは、C 関数が最初の 0 バイトで停止するため、C 関数に渡されると途中で切り捨てられる可能性があることを意味します。たとえば、不要な文字を除外またはエスケープするために C 関数を使用しようとすると、これはセキュリティに影響を与える可能性があります。

  2. std::string::c_str() の結果は、文字列を変更する操作 (非 const メンバー関数) によって無効になることがあります。最初に c_str() を使用して文字列を変更した後でこのポインタを使用しようとすると、バグ ("Heisenbugs") の診断が非常に難しくなります。

  3. 絶対に使用しないconst_castでください。goto面倒が少ないです。

于 2011-04-12T09:17:09.340 に答える