6

現在、非常に古い C++/CLI コード (旧構文 .NET ベータ) を掘り下げていて、次のようなものを見て少し驚きました。

System::String ^source("Test-String");
printf("%s", source);

プログラムは正しく出力します

Test-String

管理された文字列ソースを に渡すことができるのはなぜでしょうか?printfさらに重要なのは、なぜそれが機能するのですか? 以下は機能しないため、コンパイラによる便利な機能であるとは思いません。

System::String ^source("Test-String");
char pDest[256];
strcpy(pDest, source);

System::String^これにより、(どういうわけか予想される)に変換できないというコンパイル エラーが発生しますconst char*。したがって、私の唯一の本当の説明は、マネージ参照を va_list に渡すことは、すべてのコンパイラ チェックを凌駕し、ネイティブ コードをだましてマネージ ヒープへのポインターを使用させるということです。はメモリ内の -ArraySystem::Stringと同様に表現されるため、機能する可能性があります。または、コンパイラは a に変換し、それを に渡します。charprintfpin_ptrprintf

String^to が自動的にマーシャリングされるとは思いませんchar*。実際のメモリ アドレスを参照せずにメモリ リークが発生するためです。

これが良い解決策ではないことはわかっています。後の Visual Studio バージョンで導入されたさまざまなマーシャリング メソッドは、より優れたアプローチを提供しますが、ここで実際に何が起こっているのかを理解することは非常に興味深いことです。

ありがとう!

4

1 に答える 1

4

コンパイラがそれをこのILに変換しているためだと思います:

call vararg int32 modopt([mscorlib]System.Runtime.CompilerServices.CallConvCdecl) printf(int8 modopt([mscorlib]System.Runtime.CompilerServices.IsSignUnspecifiedByte) modopt([mscorlib]System.Runtime.CompilerServices.IsConst)*, ..., string)

これは最終的に への pinvoke 呼び出しにprintfなるため、ランタイムはそれをマーシャリングすることで少しこっそりとしています。まだマネージド ランタイムであり、ランタイムは必要に応じてマーサリングをサービスとして提供します。


いくつかのメモ:

clr!GenericPInvokeCalliHelperx86 .NET 4 Workstation CLRでこのリフティングを行っているようです。

以下は機能しません

それはストレートな C++ だからです。必要がないため、マーシャリングを行う機会はありません。

于 2012-08-06T15:51:54.837 に答える