C++ 调用C/++函数时的观察和混淆

C++ 调用C/++函数时的观察和混淆,c++,c,function,pointers,syntax,C++,C,Function,Pointers,Syntax,为什么可以这样调用C/C++函数: (&myAwesomefunction)(arg1,arg2,arg3...); 当然,获取函数的地址会给您一个指针/地址。据我所知,指针不能作为函数调用。到底发生了什么 这是否意味着我可以像函数一样调用任何地址 // Is this legal? int x = 69; (&x)(3,78,69.456,'c','o','n','d','o','m'); myAwesomefunction(arg1,arg2,arg3...); 这意味

为什么可以这样调用C/C++函数:

(&myAwesomefunction)(arg1,arg2,arg3...);
当然,获取函数的地址会给您一个指针/地址。据我所知,指针不能作为函数调用。到底发生了什么

这是否意味着我可以像函数一样调用任何地址

// Is this legal?
int x = 69;
(&x)(3,78,69.456,'c','o','n','d','o','m');
myAwesomefunction(arg1,arg2,arg3...);

这意味着什么?

是的,第一个是合法的,因为&myAwesomefunction将是指向具有已知签名的函数的指针。C++使您可以使用与调用函数相同的语法来调用函数指针。

第二个例子是不合法的,因为C++知道x是一个整数的指针,不是函数。 第一个例子怎么可能?编译器知道每个表达式的类型。我知道myAwesomefunction是一个函数名。它知道&myAwesomefunction将是一个指针,指向myAwesomefunction,并具有与myAwesomefunction相同的签名。然后,它将检查,并知道如果您有一个函数指针,那么唯一的逻辑意义就是函数调用。它可以确保函数中的内容与函数的签名相匹配


没有歧义,编译器也没有理由在调用函数指针之前强迫您取消引用它。如果在函数指针后使用括号,编译器可以计算出它是函数调用。

相反,指向函数的指针是唯一可以作为函数调用的东西。函数调用运算符的定义开始于:

表示被调用函数的表达式应具有类型 指向返回void或返回其他对象类型的函数的指针 而不是数组类型

这意味着您的第二个假设是不合法的,因为&x没有指向任何类型函数的指针类型

所以,您可能会问,为什么还可以调用这样的函数,其中myAwesomefunction是声明为函数的标识符

// Is this legal?
int x = 69;
(&x)(3,78,69.456,'c','o','n','d','o','m');
myAwesomefunction(arg1,arg2,arg3...);
答案是像myAwesomefunction这样的标识符是一个主要表达式,它的计算结果是一个函数指示符。函数指示符的定义是:

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

正式地说,当您编写myAwesomefunctionarg1、arg2、arg3。。。;,myAwesomefunction求值为函数指示符,然后将其转换为指向该函数的指针,然后使用该指针调用该函数


将函数指示符转换为指向函数的指针类似于将数组类型的表达式转换为指向数组第一个元素的指针。

我不会将一种语言称为断章取义,并期望从了解该语言的人那里得到答案。阅读常见问题解答。您可以将任何指针作为带强制转换的函数调用,但如果它不是有效的函数指针,则是未定义的行为。如果函数不是内存中的地址,您会有什么印象?C类型系统非常完美,因为它让您告诉编译器我知道我在做什么,不要限制我。如果你真的不知道自己在做什么,那你就完蛋了,但那是你的错。类型为一种语言提供了大量有用的功能,而且当你进行原始转换时,你不会完全删除类型系统,或者其他任何你通常不赞成的事情,因为你列出的原因,但在特定的实例中你会覆盖它。另外,您可以在需要时完全重写类型系统的原因是,它的类型完全是编译时概念。在运行时,没有类型信息与数据一起存储,这就是为什么C速度如此之快的部分原因。简而言之,如果您不喜欢编写可移植程序集的功能,或者无法处理编写可移植程序集的复杂性,那么C不适合您。