http://www.blogcn.com/user8/flier_lu/index.html?id=2602611&run=.09D4C2F
C++ 语言因为缺省使用 cdecl 调用方式,故而可以很方便实现参数可变参数。详细的原理可以参考我另外一篇文章 《The history of calling conventions
》 。具体到使用上,就是我们最常用的 printf 系列函数:
对应到 C# 中,则是通过 params 关键字模拟类似的语法:
可以看到,这个 params 关键字实际上是将传递数组的语义,在 C# 编译器一级做了语法上的增强,以模拟 C++ 中 ... 的语法和语义。在 IL 代码一级仔细一看就一目了然了。
这种 syntax sugar 在 C# 这个层面来说应该是足够满足需求了的,但如果涉及到与现有 C++ 代码的交互等问题,其模拟的劣势就暴露出来了。例如前面所提到的 printf 函数的 signature 就不是使用模拟语法的 params 能够处理的。MSDN 中给出的解决方法是:
通过定义多个可能的函数原型,来枚举可能用到的形式。这种实现方式感觉真是 dirty 啊,用中文形容偶觉得“龌龊”这个词比较合适,呵呵。
但是实际上 C# 或者说 CLR 的功能绝非仅此而已,在 CLR 一级实际上早已经内置了处理可变数量参数的支持。
仔细查看 CLR 的库结构,会发现对函数的调用方式实际上有两种描述:
System.Runtime.InteropServices.CallingConvention 是在使用 DllImport 属性定义外部引用函数时用到的,故而使用的名字都是与现有编程语言命名方式类似的。而 System.Reflection.CallingConventions 则是内部用于 Reflection 操作的,故而使用的名字是直接与 CLR 中方法定义对应的。
这儿的 CallingConventions.VarArgs 正是解决我们问题的关键所在。在随 .NET Framework SDK 提供的 Tool Developers Guide 中,Partition II Metadata.doc 文档中是这样介绍 VarArgs 调用方式的:
可以看到在 CLR 一级实际上是提供了对参数数目可变参数的支持的,只不过 C# 的 params 关键字因为某些原因并没有使用。而如果你考察 Managed C++ 的实现,就会发现其正是使用这个机制。
编译成 Managed 代码后,其函数 signature 如下:
C++ 语言因为缺省使用 cdecl 调用方式,故而可以很方便实现参数可变参数。详细的原理可以参考我另外一篇文章 《The history of calling conventions
》 。具体到使用上,就是我们最常用的 printf 系列函数:
|
对应到 C# 中,则是通过 params 关键字模拟类似的语法:
|
可以看到,这个 params 关键字实际上是将传递数组的语义,在 C# 编译器一级做了语法上的增强,以模拟 C++ 中 ... 的语法和语义。在 IL 代码一级仔细一看就一目了然了。
|
这种 syntax sugar 在 C# 这个层面来说应该是足够满足需求了的,但如果涉及到与现有 C++ 代码的交互等问题,其模拟的劣势就暴露出来了。例如前面所提到的 printf 函数的 signature 就不是使用模拟语法的 params 能够处理的。MSDN 中给出的解决方法是:
|
通过定义多个可能的函数原型,来枚举可能用到的形式。这种实现方式感觉真是 dirty 啊,用中文形容偶觉得“龌龊”这个词比较合适,呵呵。
但是实际上 C# 或者说 CLR 的功能绝非仅此而已,在 CLR 一级实际上早已经内置了处理可变数量参数的支持。
仔细查看 CLR 的库结构,会发现对函数的调用方式实际上有两种描述:
|
System.Runtime.InteropServices.CallingConvention 是在使用 DllImport 属性定义外部引用函数时用到的,故而使用的名字都是与现有编程语言命名方式类似的。而 System.Reflection.CallingConventions 则是内部用于 Reflection 操作的,故而使用的名字是直接与 CLR 中方法定义对应的。
这儿的 CallingConventions.VarArgs 正是解决我们问题的关键所在。在随 .NET Framework SDK 提供的 Tool Developers Guide 中,Partition II Metadata.doc 文档中是这样介绍 VarArgs 调用方式的:
以下为引用:
vararg Methods
vararg methods accept a variable number of arguments. They shall use the vararg calling convention (see Section 14.3).
At each call site, a method reference shall be used to describe the types of the actual arguments that are passed. The fixed part of the argument list shall be separated from the additional arguments with an ellipsis (see Partition I).
The vararg arguments shall be accessed by obtaining a handle to the argument list using the CIL instruction arglist (see Partition III). The handle may be used to create an instance of the value type System.ArgIterator which provides a typesafe mechanism for accessing the arguments (see Partition IV).
|
可以看到在 CLR 一级实际上是提供了对参数数目可变参数的支持的,只不过 C# 的 params 关键字因为某些原因并没有使用。而如果你考察 Managed C++ 的实现,就会发现其正是使用这个机制。
|
编译成 Managed 代码后,其函数 signature 如下:
|