此问题以某种方式与此one相关联。
我的上一个修订版显示,无法调用返回函数的数组的段落可能有一些实际用法。记住这个($ 6.5.2.2.1):
表示被调用函数的表达式应具有类型 函数返回void或返回完整对象类型的指针 除了数组类型。
返回数组的函数的局限性仅涉及函数“声明符”和“定义”。但是,如果我们看一下强制转换操作符,就没有规则禁止“函数类型”,它们返回数组作为“类型名称”。
看看'$ 6.5.4.2':
6.5.4投射算子
语法
铸表达:
unary-expression ( type-name ) cast-expression
约束
除非类型名称指定了void类型,否则类型名称应为 指定原子,限定或非限定标量类型,以及操作数 应具有标量类型。
现在,如果我们看一下'$ 6.2.5.21':
21 算术类型和指针类型统称为标量 类型即可。数组和结构类型统称为聚合 类型。
然后在'$ 6.2.5.20':
- 函数类型描述具有指定返回类型的函数。一个 函数类型的特点是返回类型和数字和 其参数的类型。据说函数类型是从中派生出来的 它的返回类型,如果返回类型为T,则函数类型为 有时被称为''函数返回T''。建设一个 返回类型的函数类型称为''函数类型 推导””。
- 指针类型可以从函数类型或对象派生 type,称为引用类型。指针类型描述对象 其值提供对引用类型的实体的引用。 有时会调用从引用类型T派生的指针类型 ''指向T''。从一个指针类型的构造 引用类型称为“指针类型派生”。指针类型 是一个完整的对象类型。
正如我所见,没有禁止这样的限制:
void *ptr;
(int (*)()[4])ptr;
或者是吗?
答案 0 :(得分:6)
我对此不太确定。请参阅Jens Gustedt的评论和我在这个答案底部的不完整分析。
通常说C不允许返回数组的函数,但强制执行此限制的唯一约束是(引用the N1570 C11 draft):
6.5.2.2p1(函数调用):
表示被调用函数的表达式应具有类型 函数返回
void
或返回完整的指针 对象类型而不是数组类型。
和6.7.6.3p1(函数声明符):
函数声明符不应指定a的返回类型 函数类型或数组类型。
(我在标准的第6部分搜索了“约束”这个词。我认为我没有错过任何东西。如果我这样做,我相信有人会指出它。)
强制转换操作符中的类型名称不是函数调用的一部分,也不是声明符,因此不适用约束。
因此,我相信这个计划:
int main(void) {
if (0) {
void *ptr;
(int (*)()[4])ptr;
}
}
严格遵守,必须由符合规定的实施方式接受。 (我添加了if (0)
以避免任何与转换的运行时语义有关的问题;将void*
转换为函数指针的行为未通过省略来定义。)
这意味着,我认为只要不在函数调用或函数声明符中使用,就允许表示返回数组的函数的类型名称或返回函数的函数。例如,它可以用于通用选择,sizeof
或_Alignof
表达式,以及其他几种情况。
这当然没用,而且可能只是委员会的疏忽。
我注意到gcc(带有-std=c11 -pedantic
的版本5.3.0)拒绝带有消息的类型名称:
type name declared as function returning an array
这似乎是一种合理的诊断,但严格来说它是不符合的,因为没有违反实际约束。
暂时离开问题的主题,gcc也抱怨道:
warning: ISO C forbids conversion of object pointer to function pointer type [-Wpedantic]
这不是严格正确的。 ISO C不禁止这样的转换;它只是没有定义它的行为。
更新:
Jens Gustedt的评论表明类型名称是声明符,因此引用返回数组的函数的类型名称违反了6.7中的约束。 6.3p1。让我们按照N1570附录A中的语法并参考那里的章节数来看一下。
约束是指“函数声明符”。由于没有名为 function-declarator 的语法生成,因此它必须引用引用函数类型的声明符。如果没有声明者,则不违反约束。
类型名称int (*)()[4]
,如果它有效,则引用一个指向函数的指针,返回一个4 int
的数组(感谢cdecl
)。
我的分析不完整。我将不得不稍后回来。