简体   繁体   English

转换为指向返回数组的函数的指针-是否允许?

[英]Casting to pointer to function returning array - is it allowed?

This question is somehow linked with this one . 这个问题是在某种程度上与此挂钩一个

My last revision shows that the paragraph stating that arrays returning functions can't be called may have some actual usage. 我的上一修订版显示了一段说明不能调用返回函数的数组的段落可能有一些实际用法。 Remember this one ($6.5.2.2.1): 请记住这一点($ 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. 表示被调用函数的表达式应具有指向函数的类型指针,该函数返回void或返回数组类型以外的完整对象类型。

The limitations of functions returning arrays concerns only function 'declarators' and 'definitions'. 返回数组的函数的局限性仅涉及函数“声明符”和“定义”。 However if we look at the cast operator, there is no rule disallowing 'function-types' which return arrays to be used as a 'type-name' in it. 但是,如果我们看一下强制转换运算符,则没有禁止“函数类型”的规则,该函数将返回数组用作其中的“类型名称”。

Look at '$6.5.4.2': 看一下'$ 6.5.4.2':

6.5.4 Cast operators 6.5.4演员

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. 除非类型名称指定了void类型,否则类型名称应指定原子,限定或不限定的标量类型 ,并且操作数应具有标量类型。

Now if we look at '$6.2.5.21': 现在,如果我们查看“ $ 6.2.5.21”:

21 Arithmetic types and pointer types are collectively called scalar types . 21 算术类型和指针类型统称为标量类型 Array and structure types are collectively called aggregate types. 数组和结构类型统称为集合类型。

And then at '$6.2.5.20': 然后在“ $ 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 ''. 据说函数类型是从其返回类型派生的,如果其返回类型为T,则有时将该函数类型称为“函数返回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 ''. 从引用类型T派生的指针类型有时被称为“ T的指针”。 The construction of a pointer type from a referenced type is called ''pointer type derivation''. 从引用类型构造指针类型的过程称为“指针类型派生”。 A pointer type is a complete object type. 指针类型是完整的对象类型。

As I see there is no constraint which forbids something like this: 如我所见,没有任何约束可以禁止这样的事情:

void *ptr;

(int (*)()[4])ptr;

Or is it? 还是?

I'm less sure of this than I was. 我比以前不太确定。 See Jens Gustedt's comment and my incomplete analysis at the bottom of this answer. 请参阅该答案底部的Jens Gustedt的评论和我的不完整分析。

It's commonly said that C does not permit functions that return arrays, but the only constraints that enforce this restriction are (quoting the N1570 C11 draft ): 通常说C不允许返回数组的函数,但是强制执行此限制的唯一约束是(引用N1570 C11草稿 ):

6.5.2.2p1 (function calls): 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. 表示被调用函数的表达式应具有指向函数的类型指针,该函数返回void或返回数组类型以外的完整对象类型。

and 6.7.6.3p1 (function declarators): 和6.7.6.3p1(函数声明符):

A function declarator shall not specify a return type that is a function type or an array type. 函数声明器不得指定函数类型或数组类型的返回类型。

(I searched for the word "Constraints" in section 6 of the standard. I don't think I missed anything. If I did, I'm confident someone will point it out.) (我在标准的第6部分中搜索了“约束”一词。我认为我没有错过任何内容。如果这样做了,我相信有人会指出这一点。)

The type-name in a cast operator is not part of a function call and is not a declarator, so neither constraint applies. 强制转换运算符中的类型名称不是函数调用的一部分,也不是声明符,因此这两个约束均不适用。

As a result, I believe that this program: 结果,我相信这个程序:

int main(void) {
    if (0) {
        void *ptr;
        (int (*)()[4])ptr;
    }
}

is strictly conforming and must be accepted by a conforming implementation. 是严格符合的,必须由符合的实现接受。 (I added the if (0) to avoid any issues regarding the run-time semantics of the conversion; the behavior of converting a void* to a function pointer is undefined by omission.) (我添加了if (0)以避免与转换的运行时语义有关的任何问题;将void*转换为函数指针的行为是不确定的。)

This means, I think, that a type-name denoting a function returning an array, or a function returning a function, is permitted as long as it's not used in a function call or function declarator. 我认为,这意味着只要函数调用或函数声明符中未使用表示类型的函数(返回数组)或函数(返回函数),就可以使用该类型名。 For example, it could be used in a generic selection, in a sizeof or _Alignof expression, and in several other contexts. 例如,它可以用于一般选择, sizeof_Alignof表达式以及其他几种上下文中。

This is, of course, not useful, and it's probably just an oversight on the part of the committee. 当然,这没有用,可能只是委员会的疏忽。

I note that gcc (version 5.3.0 with -std=c11 -pedantic ) rejects the type-name with a message: 我注意到gcc(带有-std=c11 -pedantic 5.3.0版本)拒绝了带有消息的类型名称:

type name declared as function returning an array

This seems like a reasonable diagnostic, but strictly speaking it's non-conforming since no actual constraint is violated. 这似乎是一种合理的诊断,但是严格来说,这是不合格的,因为没有违反任何实际约束。

Veering off the topic of the question for a moment, gcc also complains: gcc暂时偏离了问题的主题,还抱怨道:

 warning: ISO C forbids conversion of object pointer to function pointer type [-Wpedantic]

which is not strictly correct. 这不是严格正确的。 ISO C doesn't forbid such a conversion; ISO C 禁止这种转换; it merely does not define its behavior. 它只是没有定义其行为。

UPDATE : 更新:

Jens Gustedt's comment suggests that a type-name is a declarator , and that therefore a type-name referring to a function returning an array violates the constraint in 6.7.6.3p1. Jens Gustedt的评论建议类型名称是一个声明符,因此,引用返回数组的函数的类型名称违反了6.7.6.3p1中的约束。 Let's take a look at that, following the grammar in N1570 Annex A and referring to the section numbers there. 让我们来看一下,遵循N1570附件A中的语法,并参考其中的章节编号。

The constraint refers to a "function declarator". 该约束是指“功能声明器”。 Since there's no grammar production called function-declarator , it must be referring to a declarator that refers to a function type. 由于没有称为function-declarator的语法生成,因此必须引用一个引用了函数类型的声明器。 If there's no declarator, then the constraint is not violated. 如果没有声明符,则不违反约束。

The type-name int (*)()[4] , if it's valid, refers to a pointer to function returning an array of 4 int s (thanks to cdecl ). 类型名称int (*)()[4] (如果有效)是指向函数的指针,该函数返回一个4 int数组(感谢cdecl )。

My analysis is incomplete. 我的分析不完整。 I'll have to come back to this later. 我得稍后再讲。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM