代码之家  ›  专栏  ›  技术社区  ›  SupAl

GCC Format属性不适用于别名为“using”的函数指针

  •  4
  • SupAl  · 技术社区  · 2 年前

    作为 ISO C++ Guidelines 建议,我们应该使用 using 而不是 typedef 。但是,最近我不得不编写一些调试日志,其中 属性 将有助于编译时诊断。

    当我尝试应用 使用 关键字,这似乎不起作用:

    using logger_cb = void(*)(const char*, va_list) 
    __attribute__ ((__format__ (__printf__, 1, 0)));
    

    错误为:

    <source>:4:48: error: expected ';' before '__attribute__'
        4 | using logger_cb = void(*)(const char*, va_list) __attribute__ ((__format__ (__printf__, 1, 0))); // <-- uncommenting this won't work
          |                                                ^~~~~~~~~~~~~~
          |                                                ;
    

    但是,使用 类型定义 它的工作原理是:

    typedef void (*logger_cb)(const char*, va_list) 
    __attribute__ ((__format__ (__printf__, 1, 0)));
    

    我无法判断我的语法是错误的,还是using关键字根本不支持这一点。一些大师知道这件事吗?

    链接到示例: https://godbolt.org/z/qWdxWq6Gx

    2 回复  |  直到 2 年前
        1
  •  2
  •   user12002570    2 年前

    当我尝试应用using关键字时,这似乎不起作用:

    的位置 可选择的 attribute-specifier-seq 必须是 之后 标识符 别名声明 。这可以从 alias declaration :

    Alias声明是具有以下语法的声明:

    using identifier attr (optional) = type-id ;  (1)     
    template < template-parameter-list >
    using identifier attr (optional) = type-id ;  (2)      
    

    attr-任意数量属性的可选序列

    从中可以看出 gram.dcl :

    alias-declaration:
    using identifier attribute-specifier-seqopt = defining-type-id ; 
    

    这意味着 标准方式 使用 using 如下所示:

    using logger_cb [[gnu::format (__printf__, 1, 0) ]] = void(*)(const char*, va_list);
    

    Working demo

        2
  •  1
  •   Artyer    2 年前

    如果切换到C++11属性语法,它将在该位置应用于函数类型 void(const char*, va_list) :

    using logger_cb = void (*)(const char*, va_list)
    [[__gnu__::__format__(__printf__, 1, 0)]];
    

    这就是应用于函数类型的标准属性所在的位置 "supposed" 去,但这个替代职位适用于 __attribute__ 语法也是:

    using logger_cb = void ([[__gnu__::__format__(__printf__, 1, 0)]] *)(const char*, va_list);
    using logger_cb = void (__attribute__ ((__format__ (__printf__, 1, 0))) *)(const char*, va_list);
    

    (需要注意的是,这只是因为它在 * ,如果 logger_cb 是函数类型的别名)


    您也可以将其应用于声明( 记录器_cb ):

    using logger_cb [[__gnu__::__format__(__printf__, 1, 0)]]
        = void (*)(const char*, va_list);
    using logger_cb __attribute__ ((__format__ (__printf__, 1, 0)))
        = void (*)(const char*, va_list);
    

    或指向指针类型 void(*)(const char*, va_list) :

    using logger_cb = void (* [[__gnu__::__format__(__printf__, 1, 0)]])(const char*, va_list);
    using logger_cb = void (* __attribute__ ((__format__ (__printf__, 1, 0))))(const char*, va_list);
    

    因为他们最终都为 __format__ 属性,但请注意,其他属性的情况并非如此。