GCC-3.4.6源代码学习笔记(58)

来源:互联网 发布:星际牛仔知乎 编辑:程序博客网 时间:2024/06/05 18:20
4.3.1.7.5.4.      内建函数类型节点

从这里开始,我们将多次看到FUNCTION_DECLFUNCTION_TYPE。正如我们所了解的,在C/C++中,函数具有类型。例如,“int a (int A);”及“int b (int B);”,这2个函数具有相同的类型(它们都可以被指针类型“int(*)(int)”所指向)。但它们是同一类型的2个不同的声明,它们的行为可以完全相异。你可以说类型有点类似接口,而声明则有些像接口下不同的实现。

在后面,我们将看到一些属性可以应用于类型,而另一些则应用于声明。这个区别即来自于类型与声明的不同之处。记住这一点。

这里第一个序列的宏为builtin-types.def中的声明创建FUNCTION_TYPE节点。看到所创建的节点保存在builtin_types中所对应的槽中。 而且对于FUNCTION_TYPE,如果参数值链表的最后一个节点不是void_list_node,那么这个函数类型不接受可变数目参数。否则,则为接受可变数目参数。

 

c_common_nodes_and_builtins (continue)

 

3336   #define DEF_PRIMITIVE_TYPE(ENUM, VALUE) /

3337     builtin_types[(int) ENUM] = VALUE;

3338   #define DEF_FUNCTION_TYPE_0(ENUM, RETURN)         /

3339     builtin_types[(int) ENUM]                          /

3340       = build_function_type (builtin_types[(int) RETURN],     /

3341                         void_list_node);

3342   #define DEF_FUNCTION_TYPE_1(ENUM, RETURN, ARG1)                          /

3343     builtin_types[(int) ENUM]                                        /

3344       = build_function_type (builtin_types[(int) RETURN],                   /

3345                         tree_cons (NULL_TREE,               /

3346                                   builtin_types[(int) ARG1], /

3347                                   void_list_node));

3348   #define DEF_FUNCTION_TYPE_2(ENUM, RETURN, ARG1, ARG2) /

3349     builtin_types[(int) ENUM]                          /

3350       = build_function_type                      /

3351         (builtin_types[(int) RETURN],                    /

3352          tree_cons (NULL_TREE,                          /

3353                 builtin_types[(int) ARG1],        /

3354                 tree_cons (NULL_TREE,                 /

3355                           builtin_types[(int) ARG2],   /

3356                           void_list_node)));

3357   #define DEF_FUNCTION_TYPE_3(ENUM, RETURN, ARG1, ARG2, ARG3)           /

3358     builtin_types[(int) ENUM]                                        /

3359       = build_function_type                                    /

3360         (builtin_types[(int) RETURN],                                  /

3361          tree_cons (NULL_TREE,                                        /

3362                 builtin_types[(int) ARG1],                      /

3363                 tree_cons (NULL_TREE,                               /

3364                           builtin_types[(int) ARG2],                 /

3365                           tree_cons (NULL_TREE,                  /

3366                                    builtin_types[(int) ARG3],    /

3367                                    void_list_node))));

3368   #define DEF_FUNCTION_TYPE_4(ENUM, RETURN, ARG1, ARG2, ARG3, ARG4) /

3369     builtin_types[(int) ENUM]                                        /

3370       = build_function_type                                    /

3371         (builtin_types[(int) RETURN],                                  /

3372          tree_cons (NULL_TREE,                                        /

3373                 builtin_types[(int) ARG1],                      /

3374                 tree_cons (NULL_TREE,                               /

3375                           builtin_types[(int) ARG2],                 /

3376                           tree_cons                                  /

3377                           (NULL_TREE,                          /

3378                            builtin_types[(int) ARG3],        /

3379                            tree_cons (NULL_TREE,                 /

3380                                    builtin_types[(int) ARG4],   /

3381                                    void_list_node)))));

3382   #define DEF_FUNCTION_TYPE_VAR_0(ENUM, RETURN)                            /

3383     builtin_types[(int) ENUM]                                        /

3384       = build_function_type (builtin_types[(int) RETURN], NULL_TREE);

3385   #define DEF_FUNCTION_TYPE_VAR_1(ENUM, RETURN, ARG1)                 /

3386      builtin_types[(int) ENUM]                                      /

3387       = build_function_type (builtin_types[(int) RETURN],            /

3388                         tree_cons (NULL_TREE,               /

3389                                   builtin_types[(int) ARG1], /

3390                                   NULL_TREE));

3391  

3392   #define DEF_FUNCTION_TYPE_VAR_2(ENUM, RETURN, ARG1, ARG2)       /

3393      builtin_types[(int) ENUM]                               /

3394       = build_function_type                             /

3395         (builtin_types[(int) RETURN],                           /

3396          tree_cons (NULL_TREE,                                 /

3397                 builtin_types[(int) ARG1],               /

3398                 tree_cons (NULL_TREE,                        /

3399                           builtin_types[(int) ARG2],          /

3400                           NULL_TREE)));

3401  

3402   #define DEF_FUNCTION_TYPE_VAR_3(ENUM, RETURN, ARG1, ARG2, ARG3)   /

3403      builtin_types[(int) ENUM]                                      /

3404       = build_function_type                                    /

3405         (builtin_types[(int) RETURN],                                  /

3406          tree_cons (NULL_TREE,                                        /

3407                 builtin_types[(int) ARG1],                      /

3408                 tree_cons (NULL_TREE,                               /

3409                           builtin_types[(int) ARG2],                 /

3410                           tree_cons (NULL_TREE,                  /

3411                                    builtin_types[(int) ARG3],    /

3412                                    NULL_TREE))));

3413  

3414   #define DEF_POINTER_TYPE(ENUM, TYPE)                    /

3415     builtin_types[(int) ENUM]                          /

3416       = build_function_type (builtin_types[(int) TYPE]);

3417   #include "builtin-types.def"

3418   #undef DEF_PRIMITIVE_TYPE

3419   #undef DEF_FUNCTION_TYPE_1

3420   #undef DEF_FUNCTION_TYPE_2

3421   #undef DEF_FUNCTION_TYPE_3

3422   #undef DEF_FUNCTION_TYPE_4

3423   #undef DEF_FUNCTION_TYPE_VAR_0

3424   #undef DEF_FUNCTION_TYPE_VAR_1

3425   #undef DEF_FUNCTION_TYPE_VAR_2

3426   #undef DEF_FUNCTION_TYPE_VAR_3

3427   #undef DEF_POINTER_TYPE

4.3.1.7.5.5.      内建函数属性的节点

GNU C中,申明在程序中被调用函数的某些状况,将帮助编译器优化函数调用并执行更仔细的检查。

关键字__attribute__允许在声明时指明特定的属性。这个关键字后跟着在双括号内的属性规范。目前在所有平台上都能用于函数的属性有:alignedalloc_sizenoreturnreturns_twicenoinlinealways_inlineflattenpureconstnothrowsentinelformatformat_argno_instrument_functionsectionconstructordestructorusedunuseddeprecatedweakmallocaliaswarn_unused_resultnonnullgnu_inlineexternally_visiblehotcoldartificialerrorwarning

GCC提供的内建函数,在编译器内部看来,与其他普通的函数没有什么区别,它们也需要某些属性虽然不是全部。和声明的其他部分相同,当在编译器内部进行处理时,声明的属性也应该是树节点的形式。因此在创建内建函数的树节点前,属性的节点先要准备好。现在我们将要创建它们。

 

c_common_nodes_and_builtins (continue)

 

3429     c_init_attributes ();

 

下面的built_in_attributes是由built_in_attribute索引的标识符数组。built_in_attribute有如下定义:

 

3036   enum built_in_attribute                                                                     in c-common.c

3037   {

3038   #define DEF_ATTR_NULL_TREE(ENUM) ENUM,

3039   #define DEF_ATTR_INT(ENUM, VALUE) ENUM,

3040   #define DEF_ATTR_IDENT(ENUM, STRING) ENUM,

3041   #define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN) ENUM,

3042   #include "builtin-attrs.def"

3043   #undef DEF_ATTR_NULL_TREE

3044   #undef DEF_ATTR_INT

3045   #undef DEF_ATTR_IDENT

3046   #undef DEF_ATTR_TREE_LIST

3047     ATTR_LAST

3048   };

 

然后在c_init_attributes中,这些宏被重新定义为:

DEF_ATTR_NULL_TREE (ENUM)构建一个NULL_TREE节点。

DEF_ATTR_INT (ENUM, VALUE)构建一个INTEGER_CST节点,具有值VALUE(以HOST_WIDE_INT表示的整数)。

DEF_ATTR_IDENT (ENUM, STRING)构建为STRING一个IDENTIFIER_NODE节点。

DEF_ATTR_TREE_LIST (ENUM, PURPOSE, VALUE, CHAIN)构建一个TREE_LIST 节点,具有给定的PURPOSEVALUECHAIN内容。

 

4258   static void

4259   c_init_attributes (void)                                                                     in c-common.c

4260   {

4261     /* Fill in the built_in_attributes array.  */

4262   #define DEF_ATTR_NULL_TREE(ENUM)            /

4263     built_in_attributes[(int) ENUM] = NULL_TREE;

4264   #define DEF_ATTR_INT(ENUM, VALUE)                                       /

4265     built_in_attributes[(int) ENUM] = build_int_2 (VALUE, VALUE < 0 ? -1 : 0);

4266   #define DEF_ATTR_IDENT(ENUM, STRING)                            /

4267     built_in_attributes[(int) ENUM] = get_identifier (STRING);

4268   #define DEF_ATTR_TREE_LIST(ENUM, PURPOSE, VALUE, CHAIN)     /

4269     built_in_attributes[(int) ENUM]                  /

4270       = tree_cons (built_in_attributes[(int) PURPOSE],    /

4271               built_in_attributes[(int) VALUE],      /

4272               built_in_attributes[(int) CHAIN]);

4273   #include "builtin-attrs.def"

4274   #undef DEF_ATTR_NULL_TREE

4275   #undef DEF_ATTR_INT

4276   #undef DEF_ATTR_IDENT

4277   #undef DEF_ATTR_TREE_LIST

4278   }

 

这些宏看上去让人有点头晕,最好让GCC为我们来展开这些宏。展开的结果如下。这些代码为内建函数产生属性。

built_in_attributes[(int) ATTR_0] =

   build_int_2 (0, 0 < 0 ? -1 : 0);

  

built_in_attributes[(int) ATTR_LIST_0] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_0],

              built_in_attributes[(int) ATTR_NULL]);

       

built_in_attributes[(int) ATTR_1] =

   build_int_2 (1, 1 < 0 ? -1 : 0);

  

built_in_attributes[(int) ATTR_LIST_1] =

  tree_cons (built_in_attributes[(int) ATTR_NULL],

             built_in_attributes[(int) ATTR_1],

             built_in_attributes[(int) ATTR_NULL]);

       

built_in_attributes[(int) ATTR_2] =

   build_int_2 (2, 2 < 0 ? -1 : 0);

 

built_in_attributes[(int) ATTR_LIST_2] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_2],

              built_in_attributes[(int) ATTR_NULL]);

       

built_in_attributes[(int) ATTR_3] =

   build_int_2 (3, 3 < 0 ? -1 : 0);

 

built_in_attributes[(int) ATTR_LIST_3] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_3],

              built_in_attributes[(int) ATTR_NULL]);

       

built_in_attributes[(int) ATTR_4] =

   build_int_2 (4, 4 < 0 ? -1 : 0);

 

built_in_attributes[(int) ATTR_LIST_4] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_4],

              built_in_attributes[(int) ATTR_NULL]);

 

built_in_attributes[(int) ATTR_LIST_1_0] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_1],

              built_in_attributes[(int) ATTR_LIST_0]);

  

built_in_attributes[(int) ATTR_LIST_1_2] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_1],

              built_in_attributes[(int) ATTR_LIST_2]);

  

built_in_attributes[(int) ATTR_LIST_2_0] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_2],

              built_in_attributes[(int) ATTR_LIST_0]);

  

built_in_attributes[(int) ATTR_LIST_2_3] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_2],

              built_in_attributes[(int) ATTR_LIST_3]);

  

built_in_attributes[(int) ATTR_LIST_3_0] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_3],

              built_in_attributes[(int) ATTR_LIST_0]);

  

built_in_attributes[(int) ATTR_LIST_3_4] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_3],

              built_in_attributes[(int) ATTR_LIST_4]);

 

built_in_attributes[(int) ATTR_CONST] = get_identifier ("const");

built_in_attributes[(int) ATTR_FORMAT] = get_identifier ("format");

built_in_attributes[(int) ATTR_FORMAT_ARG] = get_identifier ("format_arg");

built_in_attributes[(int) ATTR_MALLOC] = get_identifier ("malloc");

built_in_attributes[(int) ATTR_NONNULL] = get_identifier ("nonnull");

built_in_attributes[(int) ATTR_NORETURN] = get_identifier ("noreturn");

built_in_attributes[(int) ATTR_NOTHROW] = get_identifier ("nothrow");

built_in_attributes[(int) ATTR_PRINTF] = get_identifier ("printf");

built_in_attributes[(int) ATTR_ASM_FPRINTF] = get_identifier ("asm_fprintf");

built_in_attributes[(int) ATTR_GCC_DIAG] = get_identifier ("gcc_diag");

built_in_attributes[(int) ATTR_GCC_CDIAG] = get_identifier ("gcc_cdiag");

built_in_attributes[(int) ATTR_GCC_CXXDIAG] = get_identifier ("gcc_cxxdiag");

built_in_attributes[(int) ATTR_PURE] = get_identifier ("pure");

built_in_attributes[(int) ATTR_SCANF] = get_identifier ("scanf");

built_in_attributes[(int) ATTR_STRFMON] = get_identifier ("strfmon");

built_in_attributes[(int) ATTR_STRFTIME] = get_identifier ("strftime");

 

built_in_attributes[(int) ATTR_NOTHROW_LIST] =

   tree_cons (built_in_attributes[(int) ATTR_NOTHROW],

              built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_NULL]);

 

built_in_attributes[(int) ATTR_CONST_NOTHROW_LIST] =

   tree_cons (built_in_attributes[(int) ATTR_CONST],

              built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_NOTHROW_LIST]);

 

built_in_attributes[(int) ATTR_PURE_NOTHROW_LIST] =

   tree_cons (built_in_attributes[(int) ATTR_PURE],

              built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_NOTHROW_LIST]);

 

built_in_attributes[(int) ATTR_NORETURN_NOTHROW_LIST] =

   tree_cons (built_in_attributes[(int) ATTR_NORETURN],

              built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_NOTHROW_LIST]);

 

built_in_attributes[(int) ATTR_MALLOC_NOTHROW_LIST] =

   tree_cons (built_in_attributes[(int) ATTR_MALLOC],

              built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_NOTHROW_LIST]);

 

built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1] =

   tree_cons (built_in_attributes[(int) ATTR_NONNULL],

              built_in_attributes[(int) ATTR_LIST_1],

              built_in_attributes[(int) ATTR_NOTHROW_LIST]);

 

built_in_attributes[(int) ATTR_NOTHROW_NONNULL_2] =

   tree_cons (built_in_attributes[(int) ATTR_NONNULL],

              built_in_attributes[(int) ATTR_LIST_2],

              built_in_attributes[(int) ATTR_NOTHROW_LIST]);

 

built_in_attributes[(int) ATTR_NOTHROW_NONNULL_3] =

   tree_cons (built_in_attributes[(int) ATTR_NONNULL],

              built_in_attributes[(int) ATTR_LIST_3],

              built_in_attributes[(int) ATTR_NOTHROW_LIST]);

 

built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1_2] =

   tree_cons (built_in_attributes[(int) ATTR_NONNULL],

              built_in_attributes[(int) ATTR_LIST_2],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1]);

 

built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1_4] =

   tree_cons (built_in_attributes[(int) ATTR_NONNULL],

              built_in_attributes[(int) ATTR_LIST_4],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1]);

 

built_in_attributes[(int) ATTR_CONST_NOTHROW_NONNULL_1] =

   tree_cons (built_in_attributes[(int) ATTR_CONST],

              built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1]);

 

built_in_attributes[(int) ATTR_PURE_NOTHROW_NONNULL_1] =

   tree_cons (built_in_attributes[(int) ATTR_PURE],

              built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1]);

 

built_in_attributes[(int) ATTR_PURE_NOTHROW_NONNULL_1_2] =

   tree_cons (built_in_attributes[(int) ATTR_PURE],

              built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1_2]);

 

built_in_attributes[(int) ATTR_MALLOC_NOTHROW_NONNULL_1] =

   tree_cons (built_in_attributes[(int) ATTR_MALLOC],

              built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1]);

  

built_in_attributes[(int) ATTR_PRINTF_1_0] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_PRINTF],

              built_in_attributes[(int) ATTR_LIST_1_0]);

  

built_in_attributes[(int) ATTR_FORMAT_PRINTF_1_0] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_PRINTF_1_0],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1]);

  

built_in_attributes[(int) ATTR_PRINTF_1_2] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_PRINTF],

              built_in_attributes[(int) ATTR_LIST_1_2]);

 

built_in_attributes[(int) ATTR_FORMAT_PRINTF_1_2] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_PRINTF_1_2],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1]);

  

built_in_attributes[(int) ATTR_PRINTF_2_0] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_PRINTF],

              built_in_attributes[(int) ATTR_LIST_2_0]);

 

built_in_attributes[(int) ATTR_FORMAT_PRINTF_2_0] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_PRINTF_2_0],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_2]);

  

built_in_attributes[(int) ATTR_PRINTF_2_3] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_PRINTF],

              built_in_attributes[(int) ATTR_LIST_2_3]);

 

built_in_attributes[(int) ATTR_FORMAT_PRINTF_2_3] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_PRINTF_2_3],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_2]);

  

built_in_attributes[(int) ATTR_PRINTF_3_0] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_PRINTF],

              built_in_attributes[(int) ATTR_LIST_3_0]);

 

built_in_attributes[(int) ATTR_FORMAT_PRINTF_3_0] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_PRINTF_3_0],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_3]);

  

built_in_attributes[(int) ATTR_PRINTF_3_4] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_PRINTF],

              built_in_attributes[(int) ATTR_LIST_3_4]);

 

built_in_attributes[(int) ATTR_FORMAT_PRINTF_3_4] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_PRINTF_3_4],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_3]);

  

built_in_attributes[(int) ATTR_SCANF_1_0] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_SCANF],

              built_in_attributes[(int) ATTR_LIST_1_0]);

 

built_in_attributes[(int) ATTR_FORMAT_SCANF_1_0] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_SCANF_1_0],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1]);

  

built_in_attributes[(int) ATTR_SCANF_1_2] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_SCANF],

              built_in_attributes[(int) ATTR_LIST_1_2]);

 

built_in_attributes[(int) ATTR_FORMAT_SCANF_1_2] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_SCANF_1_2],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1]);

 

built_in_attributes[(int) ATTR_SCANF_2_0] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_SCANF],

              built_in_attributes[(int) ATTR_LIST_2_0]);

 

built_in_attributes[(int) ATTR_FORMAT_SCANF_2_0] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_SCANF_2_0],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_2]);

  

built_in_attributes[(int) ATTR_SCANF_2_3] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_SCANF],

              built_in_attributes[(int) ATTR_LIST_2_3]);

 

built_in_attributes[(int) ATTR_FORMAT_SCANF_2_3] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_SCANF_2_3],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_2]);

  

built_in_attributes[(int) ATTR_STRFTIME_3_0] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_STRFTIME],

              built_in_attributes[(int) ATTR_LIST_3_0]);

 

built_in_attributes[(int) ATTR_FORMAT_STRFTIME_3_0] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_STRFTIME_3_0],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_3]);

  

built_in_attributes[(int) ATTR_STRFMON_3_4] =

   tree_cons (built_in_attributes[(int) ATTR_NULL],

              built_in_attributes[(int) ATTR_STRFMON],

              built_in_attributes[(int) ATTR_LIST_3_4]);

 

built_in_attributes[(int) ATTR_FORMAT_STRFMON_3_4] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT],

              built_in_attributes[(int) ATTR_STRFMON_3_4],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_3]);

 

built_in_attributes[(int) ATTR_FORMAT_ARG_1] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT_ARG],

              built_in_attributes[(int) ATTR_LIST_1],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_1]);

 

built_in_attributes[(int) ATTR_FORMAT_ARG_2] =

   tree_cons (built_in_attributes[(int) ATTR_FORMAT_ARG],

              built_in_attributes[(int) ATTR_LIST_2],

              built_in_attributes[(int) ATTR_NOTHROW_NONNULL_2]);

不过,仍然让人惊讶需要如此多的代码来产生这些ATTR_FORMAT_FUNC_NUM_NUM节点。为了更清楚地看到这些节点,我们在下图显示了其中的一部分,我们将与ATTR_FORMAT_PRINTF_1_0相关的节点标记为红色。

37:内建函数属性

4.3.1.7.5.5.1.              内建函数属性的细节

为了更好地理解这些内建函数,从【6】摘录的,有文档记载的属性的,详细描述陈列如下:

format (archetype, string-index, first-to-check)

这个格式属性表示一个接受printfscanfstrftimestrfmon形式参数的函数,这些参数应该按格式字符串进行类型检查。例如,声明:

extern int

my_printf (void *my_object, const char *my_format, ...)

__attribute__ ((format (printf, 2, 3)));

将促使编译器检查调用my_printf的参数与printf形式的格式字符串参数my_format一致。

参数archetype确定如何解释格式字符串,它只能取printfscanfstrftimestrfmon(你也可以使用__printf____scanf____strftime____strfmon__)。参数string-index 表明哪个参数是格式字符串(计数从1开始),而first-to-check是第一个按格式字符串进行检查的参数的序号。对于那些没有可检查参数的函数(例如vprintf(1)),则指定这个参数为0。在这种情况下,编译器只检查格式字符串的一致性。对于strftime格式,第三个参数要求必须为0。因为非静态的C++方法(method)有隐含的this指针参数,当确定string-index first-to-check的值时,这些方法的参数应该从2开始计算,而不是1

在上面的例子中,格式字符串(my_format)是函数my_print的第二个参数,而需要检查的参数从第三个开始,因此格式属性正确的参数是23

格式属性允许你指出自己的接受格式字符串作为参数的函数,因而GCC可以检查这些函数的调用中的错误。当要求给出相应的警告(使用-Wformat),编译器总是(除非使用了-ffreestanding-fno-builtin)为标准库函数printffprintfsprintfscanffscanfsscanfstrftimevprintfvfprintfvsprintf检查格式,因此不需要改变头文件stdio.h C99模式中,函数snprintfvsnprintfvscanfvfscanfvsscanf也都被检查。除了在严格符合C标准模式外,X/Open函数strfmon也象printf_unlockedfprintf_unlocked那样检查。

目标平台可能会提供额外的格式类型的检查。

 

注(1):vprintf的声明是:int vprintf(const char *restrict format, va_list ap);

format_arg (string-index)

format_arg属性表示一个接受printfscanfstrftimestrfmon风格的格式字符串,并修改它(例如,将它翻译至另一种语言)的函数。因此其结果能传递给printfscanfstrftimestrfmon风格的函数(连同没转换的参数传给格式函数,这些参数与未修改字串中的相同)。例如,声明:

extern char *

my_dgettext (char *my_domain, const char *my_format)

__attribute__ ((format_arg (2)));

促使编译器检查调用printfscanfstrftimestrfmon类型函数的参数,而这些函数的格式字符串是对my_dgettext函数的调用,以使之与my_format格式字符串一致。如果format_arg属性没有被指定,编译器在这样对格式函数的调用中,所能告知将是格式字符串参数不是常量;当使用了-Wformat-nonliteral时,这将产生一个警告,不过没有这个属性,调用就不会被检查。

参数string-index指明哪个参数是格式字符串参数(从1开始计算)。因为非静态的C++方法(method)有隐含的this指针参数,类似方法的参数应该从2开始计算。format-arg 属性允许你指出自己的修改格式字符串的函数,因而GCC可以检查对printfscanfstrftimestrfmon类型函数的调用,它们的实参则是对你函数的调用。编译器总是按这种方式处理gettextdgettextdcgettext,除非通过-ansi或合适的-std选项,或使用-ffreestanding-fno-builtin来要求严格的ISO C支持。

malloc

malloc属性用于告诉编译器一个函数应该这样处理,它所返回的非空指针不会是其他有效指针的别名。这通常会改进优化。具有这个特性的标准函数包括malloccalloc 类似realloc的函数也有这个特性,只要在函数返回非空值后,旧的指针不再被引用。

nonnull (arg-index, ...)

nonnull属性指明某些函数参数是非空指针。例如,声明:

extern void *

my_memcpy (void *dest, const void *src, size_t len) __attribute__((nonnull (1, 2)));

促使编译器检查在调用my_memcpy中,参数destsrc都是非空的。如果编译器确认一个空指针被传给一个标记为非空的参数,并且启动了-Wnonnull选项,则给出一个警告。编译器也可能选择执行优化,基于了解特定的函数参数不会为空。

如果没有对nonnull属性给出参数索引链表,那么所有的指针参数都标记为非空。为了说明这一点,下面的声明与前一个例子是等同的:

extern void *

my_memcpy (void *dest, const void *src, size_t len) __attribute__((nonnull));

noreturn

少数标准库函数,例如abortexit,不会返回。GCC自动地知道这一点。一些程序定义可它们自己的不会返回的函数。你可以声明它们为不返回的,以告诉编译器这个事实。例如,

void fatal () __attribute__ ((noreturn));

void

fatal (/* . . . */) {

/* . . . */ /* Print error message. */ /* . . . */

exit (1);

}

关键字noreturn告诉编译器假设fatal不会返回。那么可以不用考虑fatal返回的情况而优化之。这会生成稍微好一些的代码。更重要的,它有助于避免关于未初始化变量的,谬误的警告。

关键字noreturn不会影响异常路径的起效:一个标记为noreturn的函数通过抛出异常或调用longjmp依然可以返回至调用者。

不能假定由调用者函数保存的寄存器会在调用非返回函数前恢复。

一个非返回函数具有void以外的返回类型是不合理的。

属性noreturn在早于2.5版本的GCC中没有实现。一个替代的,能在当前及更旧版本工作的,声明一个函数不返回的,方式如下:

typedef void voidfn ();

volatile voidfn fatal;

但这个方式在GNU C++下不工作。

nothrow

nothrow属性用于告诉编译器一个函数不会抛出异常。例如,在标准C库中的绝大部分函数可以保证不会抛出异常,除了qsort bsearch,它们接受函数指针作为参数。Nothrow属性在早于GCC 3.3的版本没有实现。

pure

许多函数除了返回值没有别的效应,而且它们的返回值依赖于参数及/或全局变量。这样的函数,像算术操作符那样,是公共子表达式消除及循环优化的理想对象。这些函数应该使用属性pure来声明。例如,

int square (int) __attribute__ ((pure));

表明调用这个假想的平方函数的次数少于程序所表示的次数,是安全的。

一些常见的pure函数的例子是strlenmemcmp。有趣的非-pure函数有带有无限循环的函数,或者函数依赖于内存或其他系统资源,它们在2个紧邻的调用间可能发生变化(例如多线程环境下的feof)。

属性pureGCC早于2.96版本中没有实现。

const

许多函数除了参数不检查其他值,而且除了返回值它们没有其他效应。基本上这是比pure属性稍微严格一些的类别,因为函数不允许访问全局内存。

注意到一个具有指针参数,并且考查所指向数据的函数,不能被声明为const。类似的,一个调用非-const函数的函数,通常也不能是const。一个返回voidconst函数是没有意义的。

属性constGCC早于2.5的版本中没有实现。一个替代的,能在当前及更早版本中工作的,声明函数没有副作用的,方式如下:

typedef int intfn ();

extern const intfn square;

这个方式在GNU C++ 2.6.0版本后不能工作,因为语言指出const必须附属于返回值。

 

原创粉丝点击