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
的整个声明放在sizeof
中int b[sizeof(void (*)( struct s { int c; } ))];
答案 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.参数或参数