强制转换为指向函数返回数组的指针 - 允许吗?

标签 c function casting language-lawyer c11

这个问题与这个 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/

相关文章:

具有扩展类型的 Java 泛型转换

c - 指针采用什么样的数据结构?

c - execvp() 系统调用未执行

在 Win32 上停止进程的最干净方法?

javascript - 无法调用函数,因为 $rootScope 未定义

Python - 循环输入

c - C 信号的实际相关性

c++ - 为什么我的 For 循环没有完成收集数据以保存在动态分配的数组中?

c++ - 铸件内的符号

C#:解决继承类与其基类之间的无效转换异常