函数声明符中的参数声明是否具有函数原型范围?

时间:2018-05-16 12:37:07

标签: c scope language-lawyer c11

C11 ISO标准(草案)第6.2.1(2)条将功能原型定义为(强调我的)

  

函数原型是函数声明,用于声明其参数的类型。

声明如void (*f)( struct s { int c; } ); 不是函数的声明(它是指向函数的指针的声明),因此标记s具有文件或块作用域(取决于此声明出现的位置)。然后,似乎以下翻译单元void (*f)( struct s { int c; } ); struct s a[42]; 应该完全符合(抛开任何可用性问题)。然而,gcc会产生一系列不完整类型的诊断数据。 (以及s将范围限制在参数列表中的警告),表明s具有函数原型范围,即使正式没有函数声明。

标准的意图是说每个函数声明符中的参数列表定义了它自己的范围(这是gcc和其他编译器似乎解释这个的方式)?这个意图是否在标准的任何地方更正式地表达?任何尚未纳入标准的缺陷报告?

这是一个语言律师问题,当然,我很欣赏这样的2偷偷摸摸的'标签声明是坏的风格。除了s在上面的a声明中是一个不完整的类型之外,范围问题也使得定义一个具有*f原型的函数是不可能的。最后,为了避免使用f本身的问题,我可以将f的整个声明放在sizeofint b[sizeof(void (*)( struct s { int c; } ))];

3 个答案:

答案 0 :(得分:1)

我们先把它作为一个类比

struct foo* x;

声明指向struct foo的指针,但该声明中的struct foo仍然是struct类型的(转发)声明。

现在

int (*f)(int);

是函数指针的声明。指针是指向基类型int ()(int)的指针,它是具有原型的函数类型。

然后

int (*g)(struct toto { int a; });

再次是函数指针的声明。指针是指向基类型int ()(struct toto { int a; })的指针,它是具有原型的函数类型。

或者总结一下,指向某事物的指针的声明也声明指针所指向的东西。

答案 1 :(得分:0)

  

因此void (*f)( struct s { int c; } );之类的声明不是函数的声明(它是指向函数的指针的声明)...

我不同意。

条款6.7.6声明者包含:

  

语法

     
      
  • 声明符:

         

    指针 opt direct-declarator

  •   
  • 直接声明符:
          标识
          (声明者)
          direct-declarator [type-qualifier-list opt assignment-expressionopt]
          direct-declarator [static type-qualifier-list opt assignment-expression]
          direct-declarator [type-qualifier-list static assignment-expression]
          direct-declarator [type-qualifier-list opt *]
          direct-declarator(参数类型列表)
          direct-declarator(identifier-list opt
  •   
  • 指针:
          * type-qualifier-listopt
          * type-qualifier-list opt 指针
    ...
  •   

我对该子句的理解是void (*f)( struct s { int c; } );确实是指针声明,但指针声明在其 direct-declarator 部分中包含函数原型定义。因此,函数原型定义的所有语义都适用。

因此struct s 的范围是指针声明的直接声明器部分的函数原型声明。 6.2.1的§4说:

  

如果出现声明标识符的声明符或类型说明符   在函数原型的参数声明列表中(不是函数的一部分)   定义),标识符有函数原型范围,终止于   函数声明者。

我们正是在这种情况下(没有定义),因此struct s声明的范围在该行的末尾结束。

所以当gcc产生一个诊断'不完整类型的数组'(以及关于s将范围限制在参数列表中的s的警告)时,gcc是完全正确的,它表明s具有函数原型范围,即使正式没有函数声明

答案 2 :(得分:-2)

实际上,参数或参数是函数原型的一部分。 函数的原型有3个主要组件。这些是 1.功能类型 2.功能名称 3.参数或参数