这个问题与这个 one 有某种联系.
我的最后一次修订表明,声明数组返回函数不能被调用的段落可能有一些实际用途。记住这个 ($6.5.2.2.1):
The expression that denotes the called function shall have type pointer to function returning void or returning a complete object type other than an array type.
返回数组的函数的局限性仅涉及函数“声明符”和“定义”。但是,如果我们查看强制转换运算符,则没有规则禁止将返回数组的“函数类型”用作其中的"typename"。
查看“$6.5.4.2”:
6.5.4 Cast operators
Syntax
cast-expression:
unary-expression ( type-name ) cast-expression
Constraints
Unless the type name specifies a void type, the type name shall specify atomic, qualified, or unqualified scalar type, and the operand shall have scalar type.
现在,如果我们查看“$6.2.5.21”:
21 Arithmetic types and pointer types are collectively called scalar types. Array and structure types are collectively called aggregate types.
然后在“$6.2.5.20”处:
— A function type describes a function with specified return type. A function type is characterized by its return type and the number and types of its parameters. A function type is said to be derived from its return type, and if its return type is T , the function type is sometimes called ‘‘function returning T ’’. The construction of a function type from a return type is called ‘‘function type derivation’’.
— A pointer type may be derived from a function type or an object type, called the referenced type. A pointer type describes an object whose value provides a reference to an entity of the referenced type. A pointer type derived from the referenced type T is sometimes called ‘‘pointer to T ’’. The construction of a pointer type from a referenced type is called ‘‘pointer type derivation’’. A pointer type is a complete object type.
正如我所见,没有任何限制会禁止这样的事情:
void *ptr;
(int (*)()[4])ptr;
或者是吗?
最佳答案
我不太确定这一点。请参阅 Jens Gustedt 的评论和我在此答案底部的不完整分析。
通常说 C 不允许返回数组的函数,但强制执行此限制的唯一约束是(引用 the N1570 C11 draft ):
6.5.2.2p1(函数调用):
The expression that denotes the called function shall have type pointer to function returning
void
or returning a complete object type other than an array type.
和 6.7.6.3p1(函数声明符):
A function declarator shall not specify a return type that is a function type or an array type.
(我在标准的第 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 的评论表明 type-name 是一个声明符,因此引用返回数组的函数的类型名称违反了 6.7 中的约束。 6.3p1。让我们看一下,按照 N1570 附件 A 中的语法并引用那里的部分编号。
约束指的是“函数声明符”。由于没有名为 function-declarator 的语法产生式,因此它必须引用一个引用函数类型的declarator。如果没有声明符,则不违反约束。
类型名称 int (*)()[4]
,如果有效,指的是指向返回 4 个 int
数组的函数的指针(感谢到 cdecl
)。
我的分析不完整。稍后我会回来讨论这个问题。
关于强制转换为指向函数返回数组的指针 - 允许吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34794682/