从C17标准草案(6.3.2.1 ¶4;删除脚注):
- function designator* 是一个具有函数类型的表达式。除非它是
sizeof
运算符或一元&
运算符的操作数,否则类型为“function returning type”的函数指示符将转换为类型为“pointer to function returning type”的表达式。 - 根据我从上面引用中省略的脚注,
sizeof f
(用于函数指示符f
)是不符合标准的。 - 请注意,C11标准还提到了
_Alignof
运算符。 - 请注意,C2 x草案还提到了
typeof
运算符。
因此(此处:f
是函数指示符; fp
是一个函数指针):
1.可以将函数的地址表示为&f
(显式)或f
(短)。
- 可以这样调用函数:
(&f)(args)
或f(args)
fp(args)
或(*fp)(args)
这里
- 左侧
(&f)(args)
/fp(args)
与在函数指针上操作的函数调用一致,并且 - 右边的
f(args)
/(*fp)(args)
与函数调用操作函数(而不是指向函数的指针)的天真假设一致。
从风格上来说
- this answer将
&f
标记为“始终冗余”, (&f)(args)
实际上未使用,并且f
/f(args)
/fp(args)
是最短的样式。
(For为了完整起见(如果其他人想要一个很好的总结),这里有一个更长的表达式列表,等价于f
:(&f)
、(*******f)
、(***&***f)
、(***&**&f)
、(&**&***f)
、(&**&**&f)
。)
但是:
什么时候有必要或有意义
*写&f
(其中f
是函数指示符)或
*write *fp
(其中fp
是函数指针)?
(By“有意义”,我的意思是程序的行为被改变了。
- 我唯一知道的情况是
sizeof &f
。(sizeof f
是非法的,尽管C语言的GCC方言允许它(至少在12.2.0版),但具有不同的语义:它似乎返回1
(?)的案件。为什么?) - 我不明白让
f
自动转换为&f
可以简化标准的措辞,并为sizeof f
提供有用的语义。(也许这个限制的存在是为了保持与typeof
的并行性,typeof
作为编译器扩展已经存在了一段时间。 - 我不知道
_Alignof
发生了什么。 - 如果
typeof
被正式添加到下一个标准中,那么typeof &f
/typeof fp
和typeof f
/typeof *fp
之间的区别显然是有意义的。
1条答案
按热度按时间2hh7jdfx1#
由于函数指示符
f
在许多情况下会自动转换为函数的地址,因此f
与&f
在语义上不同的唯一时间是在不转换时。根据C 2018 6.3.2.1 4,这些是当它是sizeof
或一元&
的操作数时。因此,我们有:sizeof f
需要一个诊断消息,因为它违反了C 2018 www.example.com 1中的约束6.5.3.4(sizeof
不应应用于具有函数类型的表达式),并且它的行为不是由C标准定义的(因为违反了约束),而sizeof &f
产生指向函数的指针的大小。(sizeof f
仍然是符合C 2018 4 7的代码,尽管不是严格符合的,因为存在接受它的C编译器。&f
产生f
的地址,而& &f
需要一个诊断消息,因为它违反了C 2018 www.example.com 1中的约束6.5.3.2(一元&
的操作数应该是函数指示符,数组下标或一元*
的结果,或者不是位字段或用regiser
声明的左值)。我不知道有C编译器接受& &f
,所以这不是严格符合的代码,除非我们可以想象并构建一个接受它的C编译器。(& &f
中的空格用于分隔标记。否则,&&
是一个单独的标记,用于逻辑AND运算符。)我对GCC接受
sizeof f
的原因的猜测是,它是允许指针上的地址运算的一部分,甚至是void *
和指向函数的指针,以支持在操作系统、调试器、程序加载器和类似的在函数和任意内存上操作的软件中使用的代码。使sizeof f
为1是设计GCC的函数指针算法的一部分,以字节为单位进行操作。(这是GCC的一个不必要的特性,因为我们可以通过要求函数和void *
的指针首先转换为字符类型的指针来支持它们的算术运算。然而,我认为它是为了支持代码实践而做的,现在已经是遗产了。)在语法级别上,
&f
与f
的不同之处在于更长,因此它可能会违反编译器的环境限制。例如,C 2018 5.2.4.1 1要求编译器在逻辑源代码行中支持4095个字符(至少在一个程序中),因此将f
更改为&f
可能会使该行超过编译器支持的长度。对于
*fp
和fp
,适用类似的推理:*fp
在很多情况下会被转换为fp
的等价物,因此只有在不转换时才会出现语义差异。因此,sizeof *fp
和sizeof fp
如上所述不同。然而,对于&
,&*fp
是函数的地址,而&fp
是指针的地址。(这假设fp
是一个对象,而不是其他不是左值的表达式。如果它不是一个对象,则会引发与上面针对&
所讨论的相同的问题。)*fp
与fp
的环境限制考虑与&f
与f
相同。