C# 不能使用 params object[] 代替 __arglist
我正在尝试调用非托管 dll。 在寻找有关此内容并尝试的信息时,我认为我可以使用 params object[] 而不是 __arglist ,所以我像下面的代码一样更改它,但得到了不同的结果。为什么这会产生不同的效果?
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
internal class Program
{
[DllImport("msvcrt.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern int printf(string format, __arglist);
[DllImport("msvcrt.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern int printf(string format, params object[] i);
static void Main(string[] args)
{
printf("Print Integer: %d\n", __arglist(10)); // Print Integer: 10
printf("Print Integer: %d\n", 10); // Print Integer: 1363904384
}
}
}
I am trying to call an unmanaged dll.
While looking for information about this and trying it, I thought I could use params object[] instead of __arglist , so I changed it like the following code, but got different results. Why does this work differently?
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
internal class Program
{
[DllImport("msvcrt.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern int printf(string format, __arglist);
[DllImport("msvcrt.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
internal static extern int printf(string format, params object[] i);
static void Main(string[] args)
{
printf("Print Integer: %d\n", __arglist(10)); // Print Integer: 10
printf("Print Integer: %d\n", 10); // Print Integer: 1363904384
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
因为他们不是同一回事。
__ arglist
是专门的,仅适用于非托管代码中的var args。参数关键字完全是其他内容,而生成的代码仅从参数列表中为您构建一个数组。它要做的就是允许您编写myFunc(p1,p2,p3)
而不是myfunc(new Object [] {p1,p2,p3})
。在您的第二个示例中,该数字可能是传递给printf的参数阵列的地址。Because they're not the same thing.
__arglist
is specifically and only for var args in unmanaged code. The params keyword is something else entirely and the generated code just builds an array for you from the list of parameters. All it is doing is allowing you to writeMyFunc(p1,p2,p3)
instead ofMyFunc(new object [] { p1, p2, p3})
. On your second example, that number is probably the address of the parameter array passed to printf.这是关于
params
和__arglist
如何工作的简要说明:当您编写时,
您实际上只需执行以下操作:
ParamArrayAttribute 只是指示编译器允许以下形式的调用:
除了调用该方法的“正确”方式之外,还会发生这种情况
编译器只需将第一个调用转换为第二个调用,它只是语法糖而已。 MyFunction 方法有 3 个参数:
另一方面,
printf
确实不采用 2 个参数,一个是字符串类型,一个是对象类型[]、printf
实际上甚至不知道 .netstring
、object
或object[]
是什么。printf
定义为:(在 C 语言中)printf
采用一个char *
类型的参数(.net 互操作自动转换 .net>string
对象转换为非托管char *
类型),然后它可以选择采用任何(非托管)类型的任意数量的附加参数。这是关键部分,这是通过将附加参数压入堆栈而不是通过将附加参数压入数组指针来发生的,这是 inperop 由于减速而认为的。 c# 不支持此功能...好吧...除非您考虑“不受支持的__arglist
关键字”,按照 Microsoft 的说法(查看 编译器错误 CS1952 嘲笑他们的纠正建议)。所以,C# 毕竟还是支持 varargs 的。现在, 1363904384 只是指向包含值 10 的数组的指针,.net inperop 认为它应该传递一个数组作为参数(在堆栈中),而 printf 希望将该值作为参数(在堆栈中)。
PS:如果您尝试传递一个对象(除了
string
)你会得到一个例外。对象数组在 .net 范围之外没有多大意义,对象通常没有意义(认为,数组确实有意义)。This is a brief explanation on how
params
and__arglist
work:When you write
You actually just do the following:
The ParamArrayAttribute just instructs the compiler to allow calls of the form:
That happens in addition to the "correct" way to call the method
The compiler simply convert the first call to the second one, it is just syntactic sugar and nothing more. The method MyFunction has 3 parameters:
On the other hand,
printf
does not take 2 arguments, one of type string and one of type object[],printf
actually does not even know what a .netstring
,object
orobject[]
even is.printf
is defined as: (in C)printf
takes one argument of Typechar *
(the .net interop automatically converts the .netstring
object to the unmanagedchar *
type), and then it can optionally take any number of additional arguments of any (unmanaged) type. Here is the crucial part, this happens by pushing the additional parameters in the stack and not by pushing an array pointer with the additional parameters, which is what the inperop thinks due to your deceleration. c# does not support this functionality... well... exept if you consider the "unsupported__arglist
keyword", as per Microsoft sayings (check out Compiler Error CS1952 to laugh at their correction suggestion). So, c# actually supports varargs afterall.Now, the 1363904384 is just the pointer to an array containing the value 10, the .net inperop thinks it should pass an array as an argument (in the stack) while printf wants to have the value as an argument (in the stack).
PS: The Interop marshals the
object[]
as anint[]
for your particular case, if you try to pass an object (besidesstring
) you will get an exception. Object arrays do not make much sense outside the scope of .net, objects in general do not make sense (thought, arrays do make sense).