C - SAL注释(prefast)以强制可变参数的数量



我有一个可变参数函数:

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(),但是有没有简单的参数计数呢?

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

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

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

    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);

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

不幸的是,

目前 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_)。因此,您唯一的机会就是游说代码分析团队为您的用例添加支持。

最新更新