Использование __arglist с переменным набором именованных параметров - PullRequest
2 голосов
/ 14 января 2009

в моем приложении у меня есть 2 слоя. Первый уровень - это унаследованная от C функция cdecl, которая использует синтаксис «...» для изменяющегося списка параметров. Единственный способ вызвать эти функции из моего уровня .Net (второй) - использовать технику DllImport. Например, функция C ниже:

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

выглядит так в C #:

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

Моя проблема в том, что иногда я хочу вызвать эту функцию с двумя дополнительными параметрами, но если один из них имеет значение 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]);

У кого-нибудь есть идеи?

Ответы [ 2 ]

2 голосов
/ 14 января 2009

Как функция C узнает, какой из них является последним параметром? Он не может знать априори , сколько существует параметров. Нужна дополнительная информация. Один из распространенных способов получения нужной информации для функций - это анализ включенного строкового параметра для подсчета спецификаторов формата, как в printf. В этом случае, если строка формата указывает только на наличие одного дополнительного параметра, функция не знает разницы между вызовом, в котором действительно был только один дополнительный параметр, и вызовом, в котором было два, или вызовом, в котором было 20. Функция должна иметь самодисциплину для чтения только одного параметра, так как это все строка формата, которая там была. Чтение большего количества приведет к неопределенному поведению.

Если то, что я описал, не работает так, как работает ваша функция, то на вызывающем конце вы мало что можете сделать для ее решения. Но если означает , как работает ваша функция, то на вызывающей стороне ничего не будет до , потому что проблем нет.

Другой вариант, поскольку вы указываете, что ваш «устаревший код завершается ошибкой при нулевых значениях», заключается в исправлении устаревшего кода, чтобы он больше не давал сбоев.

Третий вариант - просто написать все четыре варианта:

 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);
 }

Более двух необязательных параметров, и код начинает становиться громоздким.

0 голосов
/ 12 марта 2011

Попробуйте преобразовать ваш System.List ToArray () перед тем, как поместить его в __arglist

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

...