【问题标题】:Why is there only pointer to function instead of var of function?为什么只有指向函数的指针而不是函数的var?
【发布时间】:2019-08-05 08:15:30
【问题描述】:

在C/C++中,我们可以声明/定义一个函数指针类型,然后声明/定义一些这种类型的变量。 但我认为这是模棱两可的。

例如:

typedef void ( *pFunc )();
// typedef void ( aFunc )();
void theFunc() {
   cout << "theFunc has been called successfully." << endl;
};

int main() {
   pFunc pf0 = theFunc;
   pFunc pf1 = &theFunc;

   pf0();
   ( *pf0 )();
   pf1();
   ( *pf1 )();
};

理论上只有pFunc pf1 = &amp;theFunc;(*pf1)();是合法的,但以上都可以通过编译。

Pascal syntax中,我们需要分别定义函数的vars或者函数指针的vars,它们的含义是不同的,而且更清晰(至少我是这么认为的)!

此外,我们不能声明/定义函数的 var 来代替函数指针的 var! 我尝试跟随但失败了。

typedef void ( aFunc )();
aFunc af0 = theFunc;

如果使用其他类型,例如 int/double,则有非常严格的语法限制我们正确使用它们。 (如果int*int不同,为什么*pf0pf0相同?!)

那么,我可以认为这是 C/C++ 标准的错误吗?

【问题讨论】:

  • 没有回答你的问题,但bug of C/C++ standard 是矛盾的。当实现不符合标准时会发生错误。
  • @dyukha - fill entire pages 的那种。自我矛盾、不一致和规范性差。通俗地称它们为 bug 并非没有道理。
  • 不是错误,但 OP 认为它不一致/模棱两可是正确的。这些隐式转换非常令人困惑。
  • @Leon:你一直提到“C/C++ 标准”。那是不存在的。有一个 C 标准和一个单独的 C++ 标准。现在,C++ 被设计为与 C在 1990 年存在 兼容,但这仅仅意味着 C++ 可以编译 C 源代码。然而,C++ 有一套完全独特的规则为什么 C 代码在 C++ 中也有效。

标签: c++ function function-pointers typedef


【解决方案1】:

一些声明的类型:

// decltype of theFunc is void ()
// decltype of &theFunc is void (*) ()
// decltype of *theFunc is void (&) ()

现在,关于您的代码,由于函数可以隐式转换为指向该函数的指针,因此我们有:

using pFunc = void(*)();
using rFunc = void(&)();

pFunc p_fct = &theFunc; // no conversion
pFunc p_fct = theFunc;  // conversion lvalue to pointer
pFunc p_fct = *theFunc; // conversion lvalue reference to pointer

rFunc r_fct = *theFunc; // no conversion
rFunc r_fct = theFunc;  // conversion lvalue to lvalue reference
rFunc r_fct = &theFunc; // ERROR: conversion pointer to lvalue reference not allowed

到目前为止的转换。现在,pFuncrFunc 类型的任何对象都是可调用对象。另外,请注意(*p_fct)(*r_fct) 都是rFunc 类型。因此,您可以按照问题中的描述调用您的函数:

p_fct();    // callable object of type pFunc
r_fct();    // callable object of type rFunc
(*p_fct)(); // callable object of type rFunc
(*r_fct)(); // callable object of type rFunc

请注意,以下内容等价于上述内容:

using Func = void ();
Func* p_fct = &theFunc; // no conversion
Func& r_fct = *theFunc; // no conversion
p_fct();                // callable of type Func* or pFunc
r_fct();                // callablel of type Func& or rFunc

编辑要从以下评论中回答问题:“为什么以这种方式排列它们”:无法复制函数(如@JohnBurger 的回答中所述)。这就是为什么你的代码:

typedef void ( aFunc )();
aFunc af0 = theFunc;

不起作用。如上所述,您可以执行以下操作:

typedef void ( aFunc )();
aFunc* af0 = &theFunc; // or theFunc, or even *theFunc

或者你可以这样做:

auto myFct = theFunc;

但请记住,myFctdecltype 仍然是 void (*)()

【讨论】:

  • 感谢您补充参考功能的用法。但我的问题是“为什么以这种方式排列它们”,而不是“如何使用它们”。我认为这有点模棱两可,而且不是很合理。是吗?
  • @Leon 因为你不能复制函数,正如约翰伯格的回答中所解释的那样。
  • @Leon,你可以简单地做 auto myFct = theFunc;这看起来像一个持有函数的变量(它是一个持有指向函数的指针的变量)。不管怎样,你为什么要这么费心有一个指向函数的指针呢?在 Pascal 中有什么不同的含义,它们的用法有什么不同?
【解决方案2】:

暂时忽略函数:想想struct

你可以有一个struct,或者一个指向struct的指针:

typedef struct {
    int x;
    int y;
} Point;

Point origin = { 0, 0 };
Point here   = { 1, 1 };
Point there  = { 2, 2 };

int main() {
   Point  centre  =  origin;
   Point *myPoint = &origin;

   centre  =  here;
   myPoint = &here;

   centre  =  there;
   myPoint = &there;
} // main()

全球共有三个Points:originherethere

main() 有两个变量:centremyPoint

centre 复制originherethere 的值。

myPoint 指向 originherethere - 它确实复制它们。

这两种思路有很大区别:一种是复制整个对象,另一种只指向另一个对象。

现在考虑函数。函数由编译器在代码中定义,并且永远不能被复制。所以没有函数变量是有意义的——它们会有多大?唯一明智的想法是指向函数的指针——这就是 C 语言提供的全部内容。

如果要定义 C 函数 typedef,请使用以下语法:

// Fn is a function that accepts a char and returns an int
int Fn(char c);

// FnType is the type of a function that accepts a char and returns an int
typedef int FnType(char c);

// Here is the definition of Fn
int Fn(char c) {
    return c + 1;
} // Fn(c)

// Now here is how you can use FnType
int main() {
    FnType *fn = &Fn;
    return fn('A');
} // main()

【讨论】:

  • 感谢您的回复! “所以拥有函数变量是没有意义的......”,我不这么认为。有兴趣的可以查看Pascal语言的相关语法。您可以将函数体视为 const 值,而函数的 var 是存储相同类型值的变量。同样,在您的示例中,我认为 {0,0} 是一个常量值,它可以存储在 var "origin" 中,也可以存储在 var "centre" 中。所以,应该“aVarOfFunc = anotherVarOfFunc = aFuncBody;”意思是与“中心 = 起源 = {0,0};”相似的语义?我认为我们不能混淆语义和实现。
  • 语法是关于语义的,而“var实际上存储了函数的地址”是关于实现的,不是吗?
  • @Leon:“作为值的函数体”非常有意义。但正如约翰指出的那样,这些“值”没有固定的大小。这就是为什么你可以有一个指向它们开头的指针,但你不能有一个通用的函数变量。请注意,在 C++ 和旧 C 代码中,sizeof(x) 是一个仅取决于 x 类型的常量。
【解决方案3】:

我想我找到了答案。

确实,c++ 标准提供了一种无需指针帮助即可声明函数类型的方法。

示例:

#include <functional>

using AFunc_t = function<void( int )>;

void theFunc( int );

AFunc_t afunc = theFunc;

我希望这可以帮助某人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-22
    • 2012-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多