有没有办法知道特定于Visual C++的可变参数函数参数数量?

3
首先,没有可移植的方法来计算va_list的长度。也许在Visual C ++的调试(未优化)配置中有一种方法可以做到这一点?
具体来说,我有一个可变参数函数:
void MyVariadic( const char* format, ... )
{
}

(我无法更改签名)我希望检测到format包含百分号字符且参数列表为空的情况(这可能意味着有人直接将任何字符串放在format的位置上,而不是使用%s),一旦我检测到这种情况,我可以使用assert()或其他方法。
在Visual C++的非优化调试版本中是否有一种方法可以实现这一点?

你能否添加另一个签名?当只提供一个字符串时,void MyVariadic(const char* plain) 更匹配。 - MSalters
@MSalters:也许可以这样做,但是重载分辨率会正确处理吗?我还想将调用转发到可变参数版本-这可能吗? - sharptooth
是的,重载解析将优先选择非变参函数而不是变参函数。这使得转发有点棘手,但在这里,您可以转发到 MyVariadic("%s", plain) 并忽略那些技巧。 - MSalters
@MSalters:我认为这很棒,特别是这种转发方式。你能把它加入回答中吗? - sharptooth
在C++11中,您可以使用template <typename ... Args> void MyVariadic(const char* format, Args&&...args) - Jarod42
3个回答

4

如果您只需要面向Visual C++的解决方案,并且目标是帮助检测不匹配的printf风格格式字符串,请考虑使用SAL Annotations。在启用了代码分析的构建中运行时,如果格式字符串和参数不匹配,将报告错误。

您需要的注释是_Printf_format_string_。可以参考stdio.hprintf的注释。

请考虑以下代码:

int i = 12;
printf("%d %s", i);

Visual C++ 2013运行代码分析报告给我

C6063缺少与说明符“2”相对应的“printf”的字符串参数。


好吧,这在我的情况下不会真正起作用 - 我想检测在编译时尚未知的字符串。例如,有人在运行时编写MyVariadic(someStringVariable),并且someStringVariable设置为带有百分号的字符串。 - sharptooth

2

问题基本上在于诸如MyVariadic(str)这样的调用,其中str是仅在运行时已知的const char[]类型。我们不能改变void MyVariadic(const char*, ...)函数的签名,但我们可以添加一个重载函数。void MyVariadic(const char*)更匹配。

void MyVariadic(const char* str)函数中向前转发到void MyVariadic(const char*, ...)比较困难。一般的解决方案是将&MyVariadic强制转换为void (*p)(const char*, ...),但在这种特殊情况下const char*是类似于printf的格式。这意味着我们可以将转发指向MyVariadic("%s", str)


我实际上尝试了在VC++和gcc(在ideone.com上)中编写这段代码,但两者都认为该调用是不明确的。 - sharptooth
你没有在main()函数内调用该函数。将MyVariadic("s");添加到main()中,它就无法编译了。 - sharptooth
@sharptooth:哎呀,你说得对。我显然忽略了某些东西,因为我非常确定未使用的可变参数会降低重载的可行性。 - MSalters
@sharptooth: 通过使用一个虚拟模板参数进行修复,签名从技术上来说保持不变。已修复 - MSalters
不必将虚拟参数放到可变函数上,同样可以放在新引入的非可变函数上。这解决了问题——原始函数保持不变,且不存在歧义。 - sharptooth

0
一种可能的方法是使用可变宏(带有硬编码限制):
#define COUNT_N(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...)    N
#define COUNT(...)   COUNT_N(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1)
// Warning: COUNT() return 1 (as COUNT(A)) :-/
#define ARG1(S, ...) S

然后做类似以下的事情:

#define MyVariadic_And_Check(...) do { \
    Check(ARG1(__VA_ARGS__), COUNT(__VA_ARGS__) - 1); \
    MyVariadic(__VA_ARGS__); } while(false) 

Check(const char* format, int count)是一个用于检查参数数量的函数。
注意:由于MyVariadic至少有const char* format,因此COUNT将给出正确的答案。

在C++11中,您可以使用类似以下的内容:

template <typename ... Args>
void MyVariadic_And_Check(const char* format, Args&&...args);

验证计数和类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接