函数指针的说明
Explanation of function pointers
我在理解一些结合函数指针和函数声明的C++语法方面有问题,即:
通常,当我们想要声明一种函数类型时,我们会做出类似的东西:
typedef void(*functionPtr)(int);
这对我来说很好。从现在开始,functionPtr 是一种类型,它代表指向函数的指针,该函数返回 void 并将 int 按值作为参数。
我们可以按如下方式使用它:
typedef void(*functionPtr)(int);
void function(int a){
std::cout << a << std::endl;
}
int main() {
functionPtr fun = function;
fun(5);
return 0;
}
我们5
打印在屏幕上。
我们得到了指向函数fun
的指针,我们将一些现有的指针分配给函数 - function
并通过指针执行该函数。凉。
现在,正如我在一些书中读到的那样,函数和指向函数的指针在某种程度上是相同的,所以实际上在声明function()
函数之后,每次我们说函数时,我们的意思是实函数和指向同一类型的函数的指针,所以下面的编译和每条指令都给出相同的结果(5 打印在屏幕上):
int main() {
functionPtr fun = function;
fun(5);
(*fun)(5);
(*function)(5);
function(5);
return 0;
}
所以现在只要我能想象,指向函数和函数的指针几乎相同,那么对我来说就没问题了。
那么我虽然,如果指向函数和实函数的指针相同,那么为什么我不能执行以下操作:
typedef void(functionPtr)(int); //removed *
void function(int a){
std::cout << a << std::endl;
}
int main() {
functionPtr fun = function;
fun(5);
return 0;
}
这给了我以下错误:
因此我明白了,prog.cpp:12:14: 警告:"void fun(int)"的声明具有"extern"并已初始化 函数Ptr 乐趣 = 函数;
由于某种原因,编译器现在明白了,乐趣已经存在了。然后我尝试以下操作:
int main() {
functionPtr fun;
fun(5);
return 0;
}
我遇到了链接错误。我不知何故理解,由于编译器现在将乐趣视为已经存在的函数,然后由于没有定义乐趣,我将得到链接错误。因此,我更改了变量的名称:
typedef void(functionPtr)(int);
void function(int a){
std::cout << a << std::endl;
}
int main() {
functionPtr function;
function(5);
return 0;
}
所以现在在主阴影全局名称函数中起作用,所以function(5)
从声明中使用functionPtr function;
它工作正常并在屏幕上打印 5。
所以现在我很震惊。为什么会这样?同样具有误导性的是,当函数指针像这样声明时:
typedef void(*functionPtr)(int);
我可以通过以下方式创建函数 Ptr 类型的函数:
functionPtr function(int a){
std::cout << a << std::endl;
}
然而,当声明类似以下内容时:
typedef void(functionPtr)(int);
使这个:
functionPtr function(int a){
std::cout << a << std::endl;
}
被编译器解释为函数返回函数。如果是这样,为什么前面的声明(typedef void(functionPtr)(int);
)知道这是一个返回void的函数,而不是返回函数Ptr的函数?
有人可以解释一下我到底发生了什么吗?
我正在使用启用了 C++14 选项的 g++ C++编译器。
嗯,这有点令人困惑。
函数类型和指向函数类型的指针确实是两种不同的类型(不比int
和指向int
的指针更相似)。但是,有一条规则,即函数类型在几乎所有上下文中衰减为指向函数类型的指针。这里 衰减松散意味着转换(类型转换和衰减之间有区别,但你现在可能对它不感兴趣)。
重要的是,几乎每次使用函数类型时,最终都会得到指向函数类型的指针。但是,请注意几乎 - 几乎每次都并非总是如此!
而你遇到一些情况,而它没有。
typedef void(functionPtr)(int);
functionPtr fun = function;
此代码尝试将一个函数(不是指针!函数!)复制到另一个函数。但是,当然,这是不可能的 - 您无法在C++中复制函数。编译器不允许这样做,我不敢相信你编译了它(你是说你有链接器错误?
现在,这段代码:
typedef void(functionPtr)(int);
functionPtr function;
function(5);
function
不会遮蔽任何东西。编译器知道它不是一个可以调用的函数指针,只是调用你的原始function
。
有趣的例子是这个,这里没有使用 typedef
:void function(int a) { // declaration and definition of 'function'
std::cout << a << std::endl;
}
int main() {
void function(int); // declaration of 'function'
function(5);
}
在C++的大多数情况下,在当地范围内重新宣布function
将给全球::function
蒙上阴影。所以期望那里出现链接器错误是有道理的 - main()::function
没有定义吧?
除了功能在这方面是特殊的。来自 [basic.scope.pdel] 中的注释:
块范围的函数声明 在块范围内带有 extern 说明符的变量声明是指作为 一个封闭的命名空间,但它们不会在该作用域中引入新名称。
因此,该代码示例完全等效于:
void function(int a) { /* ... */ }
void function(int ); // just redeclaring it again, which is ok
int main() {
function(5);
}
您还可以通过将全局function
放入某个命名空间来验证这一点,N
.此时,本地范围声明会向::
添加一个名称,但它没有定义 - 因此您确实会收到链接器错误。
你提到的另一个有趣的事情是函数到指针转换的概念,[conv.func]:
函数类型 T 的左值可以转换为类型为"指向 T 的指针"的 prvalue。结果是一个指向 函数。
当你有一个函数调用表达式时 - 如果你调用的东西是函数类型,它首先被转换为指向函数的指针。这就是为什么这些是等效的:
fun(5); // OK, call function pointed to by 'fun'
(*fun)(5); // OK, first convert *fun back to 'fun'
function(5); // OK, first convert to pointer to 'function'
(*function)(5); // OK, unary* makes function get converted to a pointer
// which then gets dereferenced back to function-type
// which then gets converted back to a pointer
让我们一一看看你的例子,以及它们的真正含义。
typedef void(functionPtr)(int);
void function(int a){
std::cout << a << std::endl;
}
int main() {
functionPtr fun = function;
fun(5);
return 0;
}
在这里,您正在为接受和int
的函数创建一个 typedef functionPtr
,并且不返回值。 functionPtr
实际上不是函数指针的 typedef,而是实际函数的 typedef。
然后你尝试声明一个新函数fun
,并分配给它function
。不幸的是,您无法分配给函数,因此这不起作用。
int main() {
functionPtr fun;
fun(5);
return 0;
}
同样,您正在使用指定的签名声明一个函数fun
。但是你没有定义它,所以你理所当然地失败了链接阶段。
typedef void(functionPtr)(int);
void function(int a){
std::cout << a << std::endl;
}
int main() {
functionPtr function;
function(5);
return 0;
}
这里发生了什么?你定义typedef
,主要写functionPtr function;
。这基本上只是您已经编写的函数的原型,function
.它重申此函数存在,但除此之外,它不执行任何操作。事实上,你可以写:
typedef void(functionPtr)(int);
void function(int a){
std::cout << a << std::endl;
}
int main() {
functionPtr function;
functionPtr function;
functionPtr function;
void function(int);
function(5);
return 0;
}
你想要多少次,它不会改变任何事情。您呼叫的function(5)
始终是一回事。
您可以在C++中做的一件事是使用这样的 typedef 声明函数的原型,但不能以这种方式定义它。
typedef void(*functionPtr)(int);
functionPtr function(int a){
std::cout << a << std::endl;
}
在这里,您定义了一个返回函数指针的函数,但随后您不返回它。根据您的设置,编译器可能会也可能不会抱怨。但同样function
与functionPtr
完全分离.你基本上已经写了
void (*)(int) function(int a) {
...
}
最后一个示例,即您有一个函数返回函数的示例,根本不允许,因为它毫无意义。
typedef void functionPtr (int);
void function (int a){
std::cout << a << std::endl;
}
int main() {
functionPtr *func;
func = function;
func(5);
return 0;
}
你可以这样使用它,我已经测试过了。关于这个问题确实有一个棘手的问题。
- 当使用通配符和null指针调用函数时,对输出的说明
- 关于C++中具有多重继承"this"指针的说明
- 指针数组说明
- 有关通过引用传递指针的说明
- 说明通过指针访问非静态类成员函数
- 了解 ARM 程序集说明和 C/C++ 指针
- 该指针操纵功能的说明
- 请求对数组中指针行为的说明
- 模板化函数指针说明
- C /参考操作员和指针中的插座连接()函数说明
- 函数指针说明
- C++指针分配说明
- C++03 12.4/12对通过指针显式调用基类析构函数有何说明
- 函数指针的说明
- 有关 c++ 中指针的说明
- 指针分配说明
- 关于指向非静态类成员的指针的说明
- 对指向函数转换的指针的说明
- 无法'this'指针从'const Line'转换为'Line &'说明?
- 关于智能指针运算符*和运算符>重载的说明