如果您真的非常非常绝望,那么这并非不可能。可变参数函数只能由 C 代码调用,并且调用必须由 C 编译器生成。举个例子:
#include <stdarg.h>
#include <stdio.h>
#pragma unmanaged
void variadic(int n, ...) {
va_list marker;
va_start(marker, n);
while (n--) {
printf("%d\n", va_arg(marker, int));
}
}
编译器会将示例调用variadic(3, 1, 2, 3);
转换为:
00D31045 push 3
00D31047 push 2
00D31049 push 1
00D3104B push 3
00D3104D call variadic (0D31000h)
00D31052 add esp,10h
请注意参数是如何在堆栈上从左到右传递的。调用后堆栈被清理。您可以使用内联汇编来模拟完全相同的调用模式。看起来像这样:
void variadicAdapter(int n, int* args) {
// store stack pointer so we can restore it
int espsave;
_asm mov espsave,esp;
// push arguments
for (int ix = n-1; ix >= 0; --ix) {
int value = args[ix];
_asm push value;
}
// make the call
variadic(n);
// fix stack pointer
_asm mov esp,espsave;
}
很简单,只是一些恶作剧来恢复堆栈指针。现在您有了一个可以从托管代码调用的适配器函数。您需要 pin_ptr<> 将数组转换为本机指针:
#pragma managed
using namespace System;
int main(array<System::String ^> ^args)
{
array<int>^ arr = gcnew array<int>(3) { 1, 2, 3};
pin_ptr<int> arrp(&arr[0]);
variadicAdapter(arr->Length, arrp);
return 0;
}
运行良好,实际上并没有那么危险,在优化的发布版本中进行了测试。请注意,如果需要 64 位代码,您就没有希望完成这项工作。