3

我有一个可变参数函数:

print_n_integers(7, 1, 2, 3, 4, 5, 6, 7);

int print_n_integers( unsigned int count, ... )
{
    // use va_start etc.
}

我想使用 Microsoft 的 SAL 注释,sal.h以便 Visual Studio 编译器在参数数量不匹配时注意到count。我可以count通过这种方式强制执行文字:

int print_n_integers (
    _Literal_ unsigned int count,
    ...
)

和 Visual Studio 至少有一些聪明的处理printf(),但是简单的参数计数有什么东西吗?

4

2 回答 2

2

我想提出一种不使用静态分析的替代方法来解决您的问题。

即使您可以获得静态分析的可变参数的计数,您仍然必须为每个调用提供正确的计数。您还必须确保所有参数都是(或可以提升为)整数。

处理同质类型列表的更自然、非可变的方法是打印一个数组:

    void print_nint(const int *arr, size_t n);

C99 兼容的编译器可以使用复合文字在现场创建数组:

    print_nint((int[]) {0, 8, 15}, 3);

这种语法适合自己包装在一个宏中:

    #define print_int(...)                                  \
        print_nint((int[]){__VA_ARGS__},                    \
            sizeof((int[]) {__VA_ARGS__}) / sizeof(int))

此宏进行计数,您可以在没有显式参数计数的情况下使用它:

    print_int(1, 2, 3.0, rand(), i++, j++);

可变参数的第二个扩展在内部使用sizeof而不是评估。在上面的行中,rand()只调用一次并且ij增加一次。浮点参数int在打印之前转换为。

Visual Studio 在2013 RC中引入了复合文字,但旧版本不支持它们。不幸的是,复合文字也会使您的代码无法用于 C++ 编译器。对于这些情况,您可以修改宏来定义一个临时数组:

    #define print_int(...) {                                            \
        int PrintMe_[] = {__VA_ARGS__};                                 \
        print_nint(PrintMe_, sizeof(PrintMe_) / sizeof(*PrintMe_));     \
    }

但是,只有在 void 上下文中调用该函数时,此策略才有效。

如果只使用宏,则数组及其大小是一致的。但是您可以发布底层实现并使用 SAL 对其进行注释:

    void print_nint(_In_reads_(n) const int *arr, size_t n);

我不提倡无缘无故地使用宏,但在这种情况下,宏起到了模板的作用;它可以减少危险的冗余。

于 2015-06-11T11:22:24.447 回答
1

不幸的是,目前 SAL 中没有针对这种情况的注释。

对 // 类函数的支持 printf被硬编码到分析器中,并分别通过scanf//注释访问(对于特殊情况,// )。因此,您唯一的机会是游说代码分析团队为您的用例添加支持。scanf_s_Printf_format_string__Scanf_format_string__Scanf_s_format_string__Printf_format_string_params__Scanf_format_string_params__Scanf_s_format_string_params_

于 2015-06-23T20:10:20.653 回答