我正在使用C编程来对抗第三方库(在HP/Mercury Loadrunner中),该库为其中一个函数提供了varargs样式的可变大小参数列表.我想调用这个函数,但我不知道我将拥有多少个参数.
我的一个前任所做的功能在某种程度上起了作用,但这里的问题是这个函数假定最坏的情况(超过3000个参数)和手动代码.
为了阐明,这是代码的(开头).我们称之为的功能是web_submit_data()
.HTTP将发布一组表单数据.在处理具有任意数量字段的动态生成的表单时,会出现此实现.(从原版中清理了一下,手动编码索引也是如此......)
web_submit_data_buffer_gazillion_items( const char *bufferName, const char *bufferValue) { const int size = 129; int i = 0; int j = 11; web_submit_data(&bufferName[i++ * size], //"some form" &bufferName[i++ * size], //"Action=https://blah.blah/form"); &bufferName[i++ * size], //"Method=POST"); &bufferName[i++ * size], //"TargetFrame="); &bufferName[i++ * size], //"RecContentType=text/html"); &bufferName[i++ * size], //"Referer=https://blah.blah/index.html"); &bufferName[i++ * size], //"Snapshot=t1.inf"); &bufferName[i++ * size], //"Mode=HTML"); ITEMDATA, // missing in action: indexes 8 through 10 &bufferName[j * size],&bufferValue[j++ * size], ENDITEM, &bufferName[j * size],&bufferValue[j++ * size], ENDITEM, &bufferName[j * size],&bufferValue[j++ * size], ENDITEM, .. (repeat the last 3 lines ad nauseum) .. &bufferName[j * size],&bufferValue[j++ * size], ENDITEM, &bufferName[j * size]); }
现在我找到了一个可能有用的外部库(http://www.dyncall.org),但我宁愿不a)完全依赖于处理器和b)尝试教Loadrunner关于外部源的链接.
编辑:原始函数使用硬编码索引而不是使用变量.如果结果太难以预测,仍然可以恢复原状.但是,由于我不太可能使用不同的编译器或硬件/操作系统来运行它,我怀疑它真的值得.
另外:我无法控制web_submit_data()的实现.所以只是将问题推到一个水平并不会削减它..
还有一点需要注意:规范web_submit_data()
使用一个名为LAST的常量来标记参数列表的结尾.原始实现不使用它.据推测,呼叫网站确实......
在CamelBones中,我使用libffi来调用objc_msgSend(),这是一个varargs函数.工作一种享受.
变长参数基本上只是指向传递给所需函数的一堆打包数据的指针.被调用函数负责解释此打包数据.
这种架构安全的方法是使用va_list宏(提到n-alexander),否则你可能会遇到各种数据类型在内存中填充的问题.
设计varargs函数的正确方法是实际上有两个版本,一个接受'...',然后提取va_list并将其传递给一个带有va_list的函数.这样,您可以根据需要动态构造参数,而可以调用该函数的va_list版本.
大多数标准IO函数都有varargs版本:vprintf for printf,vsprintf for sprintf ...你明白了.查看您的库是否实现了名为"vweb_submit_data"的函数或类似的效果.如果他们不这样做,请给他们发电子邮件并告诉他们修理他们的库.
3000条相同的东西(即使它是预处理器引起的)让我感到畏缩