什么时候有必要或有意义为函数 f 编写 &f 或为函数指针 fp 编写 *fp (除了:sizeof &f)?

Lov*_*ure 9 c function-pointers language-lawyer

来自 C17 标准草案(6.3.2.1 \xc2\xb64;脚注已删除):

\n
\n

函数指示符是具有函数类型的表达式。除非它是运算sizeof符或一元&运算符的操作数,否则类型为“函数返回类型”的函数指示符将转换为类型为“指向函数返回类型的指针”的表达式。

\n
\n
    \n
  • 根据我从上面引用中省略的脚注,sizeof f(对于函数指示符f)是不符合标准的。
  • \n
  • 请注意,C11 标准还提到了_Alignof运算符。
  • \n
  • 请注意,C2x 草案还提到了typeof操作员。
  • \n
\n

结果(这里:f是函数指示符;fp是函数指针):

\n
    \n
  1. 可以将函数地址指示为&f(显式)或f(短)。
  2. \n
  3. 可以将函数调用如下:\n
      \n
    • (&f)(args)或者f(args)
    • \n
    • fp(args)或者(*fp)(args)
    • \n
    \n
  4. \n
\n

这里,

\n
    \n
  • 左手(&f)(args)/fp(args)与技术上操作函数指针的函数调用一致,并且
  • \n
  • 右边的f(args)/(*fp)(args)与函数调用对函数(而不是指向函数的指针)进行操作的天真的假设是一致的。
  • \n
\n

从风格上来说,

\n
    \n
  • 这个答案被标记&f为“总是多余的”,
  • \n
  • (&f)(args)实际中几乎没有使用,
  • \n
  • f//f(args)​(*fp)(args)样式,并且
  • \n
  • f//f(args)​fp(args)最短的样式。
  • \n
\n

(为了完整起见(并且以防其他人想要一个很好的总结),这里有一个更长的表达式列表,它们相当于f:(&f), (*******f), (***&***f), (***&**&f), (&**&***f),(&**&**&f)。)

\n

但是:
\n什么时候有必要或有意义

\n
    \n
  • 写&f(其中f是函数指示符)或
  • \n
  • write *fp(fp函数指针在哪里)?
  • \n
\n

(“有意义”是指程序的行为被改变。)

\n
    \n
  • 我所知道的唯一案例是sizeof &f。(sizeof f是非法的,尽管 C 的 GCC 方言允许这样做(至少从版本 12.2.0 开始),但具有不同的语义:它似乎返回1在所有(?)情况下都会返回。为什么?)\n
      \n
    • 我不明白这一点。让f自动转换&f可以让我们简化标准的措辞并提供sizeof f有用的语义。(也许这个限制的存在是为了保持与typeof,它作为编译器扩展已经存在了一段时间。)
    • \n
    \n
  • \n
  • 关于发生的事情_Alignof,委员会在C11中犯了一个错误,所以他们在C17中纠正了它。基本上:与 不同sizeof,_Alignof仅接受带括号的类型作为其参数,但不接受表达式(C11 草案,6.5.3 \xc2\xb61)。另请参阅SO 上的这篇文章。
  • \n
  • 如果在下一个标准中正式添加到C中, /和/typeof之间的区别typeof &ftypeof fptypeof ftypeof *fp显然是有意义的。
  • \n
\n

Eri*_*hil 7

由于在许多情况下函数指示符f会自动转换为函数的地址,因此f语义上唯一与 不同的情况&f是不进行转换的情况。sizeof根据 C 2018 6.3.2.1 4,这些是当它是or 一元的操作数时&。因此我们有:

\n
    \n
  • sizeof f需要诊断消息,因为它违反了 C 2018 6.5.3.4 1 中的约束(sizeof不得应用于具有函数类型的表达式),并且其行为不是由 C 标准定义的(因为违反约束),而sizeof &f产生大小指向函数的指针。(sizeof f尽管不严格符合C 2018 4 7 的代码,但仍然符合 C 2018 4 7 的代码,因为存在接受它的 C 编译器。)
  • \n
  • &ff产生while的地址& &f需要诊断消息,因为它违反了 C 2018 6.5.3.2 1 中的约束(一元的操作数&应为函数指示符、数组下标或一元的结果*,或除位字段或之外的左值)一个用register) 声明。我不知道 C 编译器接受& &f,所以这不是严格符合代码,除非我们可以想象并构造一个接受它的 C 编译器。( 中 的空格& &f用于分隔标记。否则&&为单个标记,用于逻辑 AND 运算符。)
  • \n
\n

我对 GCC 接受的原因的猜测sizeof f是,它是允许对指针(甚至void *是函数指针)进行地址算术的一部分,以支持操作系统、调试器、程序加载器以及在函数和任意内存上操作的类似软件中使用的代码。使sizeof fbe 1 是设计GCC\xe2\x80\x99s 函数指针算术以字节为单位进行操作的一部分。(这是 GCC 的一个不必要的功能,因为我们可以支持函数指针的算术运算,并void *要求它们首先转换为指向字符类型的指针。但是,我认为这样做是为了支持当时的代码实践,并且现在已成为遗产。)

\n

在语法级别,&f不同之处f在于更长,因此它可能会违反编译器的环境限制。例如,C 2018 5.2.4.1 1 要求编译器支持逻辑源行(至少在一个程序中)中的 4095 个字符,因此更改f为&f可能会使该行超过编译器支持的长度。

\n

对于*fpvs fp,适用类似的推理:在许多情况下*fp被转换为等效的fp,因此仅当它不是时才会出现语义差异。因此sizeof *fp和sizeof fp与上面讨论的不同。然而, for &,&*fp是函数的地址,而&fp是指针的地址。(这假设这fp是一个对象,而不是其他不是左值的表达式。如果它不是一个对象,它会引发与讨论相同的问题&上面讨论的相同的问题。)

\n

与*fp与具有相同fp的环境限制考虑。&ff

\n