none
C++のDLLで配列の引数を持つ関数があります。C#で outを指定できないのですか? RRS feed

  • 質問

  • C++のDLLの関数で、配列の引数があります。
    値を受けとるだけなので、C#のラッパーで、Prog(out int[] tbl)
    のようにしたいのですが、outは指定できないものなのですか?

    2012年7月11日 1:03

回答

  • C++側
    void CppProg( int AnsTbl[])     利用側はこの値を貰うだけ。

    C#側
    (略)
    public static extern void CppProg(out int[] AnsTbl);
    のようにして、
    aClass.CppProg( out AnsTbl )
    のようなコーディングにならないかなということです。

    少しとらえ違いをしていませんか?
    C++ の関数は、利用側が配列を確保して中で書き換えるシグネチャになっていますよね。
    C# の out キーワードの場合、関数の中で配列を確保するシグネチャになります。
    このように考えると、C++ の関数のシグネチャが変わらない限り、それはできないということになります。

    > [Out] Hoge[] hogeと記述できます。
    public static extern void CppProg([Out] int[] AnsTbl);
    とした方が良いということですか?

    細かい挙動はわかりませんが、環境によっては、コピーされた配列が C++ 側に渡ってしまい、書き換えた結果を入手できない恐れがあります。そのため、Out 属性をつけることで結果が欲しいことを明示した方が安全だと言うことです。

    • 回答としてマーク クサキ 2012年7月12日 0:21
    2012年7月11日 13:32
    モデレータ

すべての返信

  • マーシャリングでHoge**からout Hoge[]に変換するには、追加情報として配列長が必要です。.NETの配列オブジェクトは自身が要素数を管理しますから。他の引数で配列長を返すパターンの場合、MarshalAs属性のSizeParamIndexを使用できます。

    で、引数が配列なら単にHoge*ではないですか? その場合、[Out] Hoge[] hogeと記述できます。(int[]ならblittableだから必ずしもOut属性は必要ないような気がしますが、常に付けることを推奨します)

    2012年7月11日 1:33
  • C++側
    void CppProg( int AnsTbl[])     利用側はこの値を貰うだけ。

    C#側
    [DllImport("ABC", EntryPoint = "CppProg")]
    public static extern void CppProg(int[] AnsTbl);
    aClass.CppProg( AnsTbl );
    これで、問題なく値を貰えているのですが、

    public static extern void CppProg(out int[] AnsTbl);
    のようにして、
    aClass.CppProg( out AnsTbl )
    のようなコーディングにならないかなということです。
    その方が値を貰うだけとハッキリし分かり可読性が高まると思います。
    また、なにより普通の変数と同じ書き方になった方が良いと思います。
    さらに、コンパイラーによる、それなりのチェックが入り良いのではと。

    > [Out] Hoge[] hogeと記述できます。
    public static extern void CppProg([Out] int[] AnsTbl);
    とした方が良いということですか?
    有ってもなくても同じ動きになりますが、
    利用する時、aClass.CppProg( AnsTbl );
    となり、思っていることとは違います。

    2012年7月11日 7:52
  • C++側
    void CppProg( int AnsTbl[])     利用側はこの値を貰うだけ。

    C#側
    (略)
    public static extern void CppProg(out int[] AnsTbl);
    のようにして、
    aClass.CppProg( out AnsTbl )
    のようなコーディングにならないかなということです。

    少しとらえ違いをしていませんか?
    C++ の関数は、利用側が配列を確保して中で書き換えるシグネチャになっていますよね。
    C# の out キーワードの場合、関数の中で配列を確保するシグネチャになります。
    このように考えると、C++ の関数のシグネチャが変わらない限り、それはできないということになります。

    > [Out] Hoge[] hogeと記述できます。
    public static extern void CppProg([Out] int[] AnsTbl);
    とした方が良いということですか?

    細かい挙動はわかりませんが、環境によっては、コピーされた配列が C++ 側に渡ってしまい、書き換えた結果を入手できない恐れがあります。そのため、Out 属性をつけることで結果が欲しいことを明示した方が安全だと言うことです。

    • 回答としてマーク クサキ 2012年7月12日 0:21
    2012年7月11日 13:32
    モデレータ
  • 補足というか愚痴というか、

    クサキさんの質問スレッドに過去何度となく、メモリ確保・メモリ解放はどちらが行うかを検討されているか指摘しています。何度指摘すれば理解してくれるんでしょうねぇ。
    http://social.msdn.microsoft.com/Forums/ja-JP/csharpgeneralja/thread/c9cc04f6-584b-48c7-bfae-d23dd2f7c7e2
    http://social.msdn.microsoft.com/Forums/ja-JP/vsgeneralja/thread/81ed3094-c101-4ee1-874c-5b93bae77235

    2012年7月11日 14:18
  • 出来ない旨わかりました。
    出来るのに私がやり方を知らないだけかと心配していましたが、スッキリしました。
    ありがとうございました。

    2012年7月12日 0:21