2

私のアプリケーションでは、2つのレイヤーがあります。最初のレイヤーは、さまざまなパラメーターリストに「...」構文を使用するcdecl関数を公開するCレガシーです。.Netレイヤー(2番目のレイヤー)からこれらの関数を呼び出す唯一の方法は、DllImportテクニックを使用することです。たとえば、以下のC関数:

int myFunc(char* name, ...);

C#では次のようになります。

[DllImport("MyDll.dll"),
 CharSet = CharSet.Ansi,
 CallingConvention = CallingConvention.Cdecl]
int myFunc(string name, __arglist);

私の問題は、2つの追加パラメーターを使用してこの関数を呼び出したい場合がありますが、そのうちの1つがNULLの場合、引数リストに含まれません(私のレガシーコードはNULL値で失敗します)。たとえば、私はこの呼び出しが必要です:

int foo(string name, string a, string b)
{
     myFunc(name, __arglist(a, b));
}

{
     foo("john", "arg1", null);
}

Cによって次のように解釈されます

myFunc("john", "arg1");

残念ながら、そのようなことをしています:

int foo(string name, string a, string b)
{
     List<string> args = new List<string>();
     if(a != null) args.Add(a);
     if(b != null) args.Add(b);
     myFunc(name, __arglist(args));
}
{
     foo("john", "arg1", null);
}

Cによって次のように解釈されます。

myFunc(name, args);

ではなく:

myFunc(name, args[0]);

誰かが何か考えを持っていますか?

4

2 に答える 2

2

C関数は、どのパラメーターが最後のパラメーターであるかをどのように認識しますか?パラメータがいくつあるかを事前に知ることはできません。追加情報が必要です。関数が必要な情報を取得する一般的な方法の1つは、のように、含まれている文字列パラメーターを解析して形式指定子をカウントすることですprintf。その場合、フォーマット文字列が追加のパラメータが1つしかないことを示している場合、関数は、実際には1つの追加パラメータしか持たない呼び出しと2つある呼び出しまたは20の呼び出しの違いを認識しません。関数には、1つのパラメーターのみを読み取る自己規律が必要です。これは、フォーマット文字列がすべてであると述べているためです。さらに読むと、未定義の動作につながります。

私が説明したことが関数の動作方法ではない場合、それを解決するために呼び出し側でできることはあまりありません。しかし、それがあなたの関数どのように機能するかであるならば、問題がないので、呼び出し側で何もすることはありません。

もう1つのオプションは、「レガシーコードがnull値で失敗する」ことを示しているため、レガシーコードが失敗しないように修正することです。

3番目のオプションは、4つの可能性すべてを単純に記述することです。

 if (a != null) {
   if (b != null)
     return myFunc(name, a, b);
   else
     return myFunc(name, a);
 } else {
   if (b != null)
     return myFunc(names, b);
   else
     return myFunc(names);
 }

ただし、3つ以上のオプションのパラメーターがあり、コードが扱いにくくなり始めます。

于 2009-01-14T16:31:47.180 に答える
0

System.List ToArray()を__arglistでラップする前に変換してみてください

myFunc(name, __arglist(args.ToArray()));

于 2011-03-12T20:12:52.177 に答える