使用__arglist和一组不同的命名参数

时间:2009-01-14 16:03:41

标签: calling-convention

在我的应用程序中我有2层。第一层是C legacy,公开了cdecl函数,它们使用“...”语法来表示变化的参数列表。我发现从我的.Net层(第二个)调用这些函数的唯一方法是使用DllImport技术。例如下面的C函数:

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

在C#中看起来像那样:

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

我的问题是,有时我想用2个额外的参数调用这个函数,但如果其中一个是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 个答案:

答案 0 :(得分:2)

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

但是,有两个以上的可选参数,代码开始变得难以处理。

答案 1 :(得分:0)

尝试在将其封装到__arglist

之前转换System.List ToArray()

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