Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/68.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 为什么函数指针定义使用任意数量的符号'&';或星号'*';?_C++_C_Function Pointers - Fatal编程技术网

C++ 为什么函数指针定义使用任意数量的符号'&';或星号'*';?

C++ 为什么函数指针定义使用任意数量的符号'&';或星号'*';?,c++,c,function-pointers,C++,C,Function Pointers,为什么要做以下工作 void foo() { cout << "Foo to you too!\n"; }; int main() { void (*p1_foo)() = foo; void (*p2_foo)() = *foo; void (*p3_foo)() = &foo; void (*p4_foo)() = *&foo; void (*p5_foo)() = &*foo; void (*p6

为什么要做以下工作

void foo() {
    cout << "Foo to you too!\n";
};

int main() {
    void (*p1_foo)() = foo;
    void (*p2_foo)() = *foo;
    void (*p3_foo)() = &foo;
    void (*p4_foo)() = *&foo;
    void (*p5_foo)() = &*foo;
    void (*p6_foo)() = **foo;
    void (*p7_foo)() = **********************foo;

    (*p1_foo)();
    (*p2_foo)();
    (*p3_foo)();
    (*p4_foo)();
    (*p5_foo)();
    (*p6_foo)();
    (*p7_foo)();
}
void foo(){

cout有几个部分允许所有这些操作符组合以相同的方式工作

所有这些工作的根本原因是函数(如
foo
)可以隐式转换为指向函数的指针。这就是
void(*p1_foo)(=foo;
工作的原因:
foo
被隐式转换为指向自身的指针,并且该指针被分配给
p1_foo

一元
&
应用于函数时,会生成指向函数的指针,就像它应用于对象时生成对象的地址一样。对于指向普通函数的指针,由于隐式函数到函数指针的转换,它总是多余的。在任何情况下,这就是
void(*p3_foo)()=&foo;
有效

一元
*
应用于函数指针时,生成指向函数,就像它应用于指向对象的普通指针时生成指向对象一样

这些规则可以组合。考虑你的第二个到最后一个例子,<代码> *Foo:

  • 首先,
    foo
    隐式转换为指向自身的指针,第一个
    *
    应用于该函数指针,再次生成函数
    foo
  • 然后,结果再次隐式转换为指向自身的指针,并应用第二个
    *
    ,再次生成函数
    foo
  • 然后,它再次隐式转换为函数指针并分配给变量
您可以添加任意数量的
*
s,结果总是一样的。越多的
*
s,越快乐

我们也可以考虑你的第五个例子,<代码>和*Fo< <代码>:

  • 首先,将
    foo
    隐式转换为指向自身的指针;应用一元
    *
    ,再次生成
    foo
  • 然后,将
    &
    应用于
    foo
    ,生成一个指向
    foo
    的指针,该指针被分配给变量
只能应用于函数,而不能应用于已转换为函数指针的函数(当然,除非函数指针是一个变量,在这种情况下,结果是指向函数的指针;例如,您可以添加到列表中
void(**pp_foo)(=&p7_foo;

这就是为什么
&&foo
不起作用的原因:
&foo
不是一个函数;它是一个函数指针,是一个右值。然而,
&*&*&*&*&*&*&*&*&*&*&*&*foo
会起作用,就像
&******&foo
一样,因为在这两个表达式中,
&
总是应用于函数,而不是右值函数指针


还要注意的是,您不需要使用一元
*
通过函数指针进行调用;
(*p1_foo)(;
(p1_foo)()
也有同样的结果,这也是因为函数到函数指针的转换。

我认为记住C只是底层机器的抽象,这是抽象泄漏的地方之一,这也是很有帮助的


从计算机的角度来看,一个函数只是一个内存地址,如果被执行,它将执行其他指令。因此,C语言中的一个函数本身就是一个地址,这可能导致一个函数是“相同”的设计正如它所指向的地址。

&
*
是对在C中声明为函数的符号的幂等运算,这意味着
func==*func===&func=*&func
,因此
*func==**func
,但它们有不同的类型,因此您将得到一个警告

传递给函数的函数地址的参数类型可以是
int()
int(*)(
),也可以是
*func
func
&func
。调用
(&func)(
)与
func()
(*func)(
)相同

*
&
对函数符号没有任何意义,编译器在这两种情况下都选择将其解释为func的地址,而不是产生错误。函数不像数组符号那样作为单独的指针存在,因此
&arr
arr
相同,因为它不是物理指针在运行时带有地址的指针,它是编译器级别的逻辑指针。此外,
*func
将读取函数代码的第一个字节,这是一个代码段,而不是产生编译器错误或允许它成为运行时错误分段错误,它只是被编译器解释为函数的地址


声明为函数指针的符号上的
&
将获得指针的地址(因为它现在是堆栈或数据部分上显示的实际指针变量),而
funcp
*funcp
仍将被解释为函数的地址。

如果您仍然对@JamesMcNellis的答案不太信服,这里有一个证明。这是AST(抽象语法树)抽象语法树是编译器内部程序结构的内部表示形式

void func1() {};
void test() {
    func1();
    (*func1)();
    (&func1)();

    void(*func1ptr)(void) = func1;
    func1ptr();
    (*func1ptr)();
    //(&func1ptr)();//error since func1ptr is a variable, &func1ptr is its address which is not callable.
}
AST:


@吉米:那些不是对函数指针的引用,它们只是函数指针。
&foo
获取
foo
的地址,这导致函数指针指向
foo
,正如人们所期望的那样。你也不能为对象链接
操作符:给定
int p;
&p
会产生一个点ter to
p
是一个右值表达式;
&
运算符需要一个左值表达式。我不同意。越是
*
,快乐就越少。请不要这样做
//func1();
|-CallExpr //call the pointer
| `-ImplicitCastExpr //implicitly convert func1 to pointer
|   `-DeclRefExpr //reference func1

//(*func1)();
|-CallExpr //call the pointer
| `-ImplicitCastExpr //implicitly convert the funtion to pointer
|   `-ParenExpr //parentheses
|     `-UnaryOperator //* operator get function from the pointer
|       `-ImplicitCastExpr //implicitly convert func1 to pointer
|         `-DeclRefExpr //reference func1

//(&func1)();
|-CallExpr //call the pointer
| `-ParenExpr //parentheses
|   `-UnaryOperator //& get pointer from func1
|     `-DeclRefExpr //reference func1

//void(*func1ptr)(void) = func1;
|-DeclStmt //define variable func1ptr
| `-VarDecl //define variable func1ptr
|   `-ImplicitCastExpr //implicitly convert func1 to pointer
|     `-DeclRefExpr  //reference func1

//func1ptr();
|-CallExpr  //call the pointer
| `-ImplicitCastExpr //implicitly convert func1ptr to pointer
|   `-DeclRefExpr //reference the variable func1ptr

//(*func1ptr)();
`-CallExpr //call the pointer 
  `-ImplicitCastExpr //implicitly convert the function to pointer
    `-ParenExpr //parentheses
      `-UnaryOperator //* get the function from the pointer
        `-ImplicitCastExpr //implicitly convert func1ptr to pointer
          `-DeclRefExpr //reference the variable func1ptr