代码之家  ›  专栏  ›  技术社区  ›  Ken P

如何利用[*]printf格式类型规范警告?

  •  3
  • Ken P  · 技术社区  · 9 月前

    众所周知,GCC能够在您尝试使用类型规范不匹配的printf()系列函数时发出警告。在我们的代码中,我们有许多形式如下的实用函数:

    int zzzprintf(DataType *dt, const char *format, ...) {
        va_list args;
        va_start(args, format);
        int status = vprintf(dt->buf, format, args);
        va_end(args);
    
        return status
    }
    

    我想看到的是围绕zzzprintf()函数的一组相同的警告语义,如果你说call:

    int64_t id64;
    zzzprintf(dt, "Hello, %d\n", id64);
    

    你会得到警告:

    /tmp/foo.c: In function ‘main’:
    /tmp/foo.c:7:20: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int64_t’ {aka ‘long int’} [-Wformat=]
         zzzprintf("Hello %d\n", id64);
                          ~^     ~~
                          %ld
    

    注意:我并不是要求对GCC编译器进行增强。我正在寻找一种方法,通过#pragma等告诉编译器预期这种行为。我们目前使用的是gcc 8.4.0,无法轻松升级gcc,因为我们暂时被锁定在Ubuntu 18.04上。

    2 回复  |  直到 9 月前
        1
  •  8
  •   ShadowRanger    9 月前

    GCC支持 Function Attributes 包括一个模仿 printf -喜欢(或 scanf , strftime ,或 strfmon )检查, format 。您可以通过在相应的头文件中这样声明您的函数来使用它:

    int zzzprintf(DataType *dt, const char *format, ...)
            __attribute__ ((format (printf, 2, 3)));
    

    这使得包括该标头在内的所有源文件都使用与以下内容关联的编译器检查来处理参数 输出函数 .

    正如顶部的链接所示,至少从GCC 4.7.2开始就支持这一点,因此您的编译器限制应该不会造成问题。

        2
  •  0
  •   Jonathan Leffler    9 月前

    这是对 ShadowRanger s answer :

    我有时在某些目标平台上使用GCC以外的编译器,因此我使用宏来封装功能。

    #if !defined(PRINTFLIKE)
    #if defined(__GNUC__)
    #define PRINTFLIKE(n, m) __attribute__((format(printf, n, m)))
    #else
    #define PRINTFLIKE(n, m) /* If only */
    #endif /* __GNUC__ */
    #endif /* PRINTFLIKE */
    
    …
    
    extern void err_logmsg(FILE *fp, int flags, int estat, const char *format, ...) PRINTFLIKE(4, 5); 
    extern void err_print(int flags, int estat, const char *format, va_list args);
    extern void err_printversion(const char *program, const char *verinfo);
    extern void err_remark(const char *format, ...) PRINTFLIKE(1, 2); 
    extern void err_report(int flags, int estat, const char *format, ...) PRINTFLIKE(3, 4); 
    extern void err_sysrem(const char *format, ...) PRINTFLIKE(1, 2); 
    

    由于我使用GCC开发,错误检查在我的开发平台上有效,我依靠它来保护我在其他平台上的安全。生活变得更容易了,因为我不再使用任何32位平台。