sal annotation(prefast)强制执行可变参数的数量

时间:2015-06-11 03:56:04

标签: c visual-studio annotations sal

我有一个可变函数:

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

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

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

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

和Visual Studio至少有一些聪明才能应对printf(),但是有一些简单的参数计数吗?

2 个答案:

答案 0 :(得分:2)

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

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

处理同质类型列表的更自然,非变量方法是打印数组:

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

C99兼容编译器可以使用compound literals

在现场创建数组
    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);

我不主张无偿使用宏,但在这种情况下,宏扮演模板的角色;它可以减少危险的冗余。

答案 1 :(得分:1)

不幸的是,在这种情况下,SAL目前没有注释。

printf / scanf / scanf_s类函数的支持已硬编码到分析器中,并通过_Printf_format_string_ / _Scanf_format_string_ / {{分别为1}}注释(对于特殊情况,_Scanf_s_format_string_ / _Printf_format_string_params_ / _Scanf_format_string_params_)。因此,您唯一的机会是游说代码分析团队为您的用例添加支持。