【问题标题】:What is the use of __attribute__ (format) in C to define a function?C中的__attribute__(格式)定义函数有什么用?
【发布时间】:2016-02-08 21:13:15
【问题描述】:

我在一个C项目中遇到过这行代码,没看懂。

#define FMT_CHK(fmt, args)  __attribute__ ((format (printf, fmt, args)))

GNU官网没有解释清楚(https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes

__attribute__ ((format ())的用途是什么,应该如何使用?

【问题讨论】:

  • 您需要哪些方面的帮助?该手册对我来说似乎很清楚,它甚至提供了如何使用它的示例,我不想将手册复制并粘贴到这里的答案中。
  • 究竟什么是 fmt 和 args?在某些示例中,fmt 为 1 或 2,args 为 2 或 3。fmt 表示“格式字符串”参数的编号,而 args 表示“第一个可变参数的编号”。我不明白,以及它将如何使用。
  • 这在 gcc 文档中有很好的解释。但是理解确实需要一些 C 基础知识。如果你不明白,你应该学习这些基础知识 - 没有冒犯。
  • 宏扩展为属性声明,并且该属性必须与函数相关联。宏的 fmtargs 参数是该函数的参数列表的索引,分别指示格式字符串和要检查格式的第一个参数的位置。
  • 还要注意,整个 __attribute__ 是 GCC 扩展,不是标准 C 的一部分。如果您从不学习或使用它,那么您可能不会受到太大影响。

标签: c gcc


【解决方案1】:

所以,fmtargs 参数只是告诉你哪个参数有格式,哪个参数有参数。

void myprintf(const char *fmt, ...);
//            ^^ fmt = arg#1
//                             ^^ args = arg#2...

所以在这种情况下,正确的属性是:

__attribute__((format(printf, 1, 2)))

如果你有更长的函数声明...

void myprintf(obj *x, const char *fmt, int level, ...)
//                    ^^ format: arg#2
//                                                ^^ args: arg#4...
    __attribute__((format(printf, 2, 4)));

【讨论】:

    【解决方案2】:

    我有一个标题stderr.h,其中包括以下内容:

    #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 NORETURN void err_abort(const char *format, ...) PRINTFLIKE(1,2);
    extern NORETURN void err_error(const char *format, ...) PRINTFLIKE(1,2);
    extern NORETURN void err_error1(const char *s1);
    extern NORETURN void err_error2(const char *s1, const char *s2);
    extern NORETURN void err_help(const char *use_str, const char *hlp_str);
    extern NORETURN void err_helplist(const char *use_str, const char * const *help_list);
    extern NORETURN void err_internal(const char *function, const char *format, ...) PRINTFLIKE(2,3);
    extern NORETURN void err_syserr(const char *format, ...) PRINTFLIKE(1,2);
    extern NORETURN void err_syserr1(const char *s1);
    extern NORETURN void err_syserr2(const char *s1, const char *s2);
    extern NORETURN void err_syserror(int errnum, const char *format, ...) PRINTFLIKE(2,3);
    
    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_remark1(const char *s1);
    extern void err_remark2(const char *s1, const char *s2);
    extern void err_report(int flags, int estat, const char *format, ...) PRINTFLIKE(3,4);
    extern void err_sysrem(const char *format, ...) PRINTFLIKE(1,2);
    extern void err_sysrem1(const char *s1);
    extern void err_sysrem2(const char *s1, const char *s2);
    extern void err_sysremark(int errnum, const char *format, ...) PRINTFLIKE(2,3);
    

    NORETURN 是另外一段条件编译,表示这些函数一旦调用就不会返回。测试稍微复杂一些,因为标准 C (ISO/IEC 9899:2011) 有一个内置机制 — _Noreturn — 可以与支持 C11 的编译器一起使用。

    #if !defined(NORETURN)
    #if __STDC_VERSION__ >= 201112L
    #define NORETURN      _Noreturn
    #elif defined(__GNUC__)
    #define NORETURN      __attribute__((noreturn))
    #else
    #define NORETURN      /* If only */
    #endif /* __STDC_VERSION__ || __GNUC__ */
    #endif /* NORETURN */
    

    请注意,当编译器不声称是 GCC (__GNUC__) 时,该机制如何保持不碍事。除非您愿意将自己完全绑定到 GCC,否则这些方面的保护性代码是必要的。

    【讨论】:

      【解决方案3】:

      来自 gcc 页面的引用:

      format 属性指定函数采用 printf、scanf、strftime 或 strfmon 样式参数,这些参数应根据格式字符串进行类型检查。

      点赞__attribute__ ((format (printf, format_param, arg_list))

      gcc 将在编译期间帮助您检查arg_list 类型是否对应于format_param

      【讨论】:

        猜你喜欢
        • 2019-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-10
        • 2018-08-17
        • 1970-01-01
        • 2021-02-23
        • 2017-02-03
        相关资源
        最近更新 更多