C语言中的函数指针和内存地址
在以下程序中,C语言中的函数指针和内存地址,c,linux,gcc,function-pointers,C,Linux,Gcc,Function Pointers,在以下程序中,&foo、*foo和foo指向相同的内存地址: #include <stdio.h> int foo(int arg) { printf("arg = %d\n", arg); return arg; } int main() { foo(0); // ok (*foo)(0); // ok (&foo)(0); // ok printf("&foo = %lx\n", (size_t)(&f
&foo
、*foo
和foo
指向相同的内存地址:
#include <stdio.h>
int foo(int arg)
{
printf("arg = %d\n", arg);
return arg;
}
int main()
{
foo(0); // ok
(*foo)(0); // ok
(&foo)(0); // ok
printf("&foo = %lx\n", (size_t)(&foo));
printf("foo = %lx\n", (size_t)(foo));
printf("*foo = %lx\n", (size_t)(*foo));
return 0;
}
有人能解释吗?
谢谢。在C标准术语中,任何具有函数类型的表达式都是函数指示符。因此,当用作表达式时,函数的名称是函数指示符 对于函数指示符,除了获取其地址外,您无法执行任何操作。不能将数字添加到函数指示符,也不能将其与另一个函数指示符进行比较,依此类推。当然,您可以调用函数,但这实际上是通过地址完成的,而不是通过指示符完成的,我稍后会解释。由于除了获取函数的地址外,您无法对函数执行任何操作,因此C会自动为您执行此操作。根据C 2018 6.3.2.1 4: 除非它是
sizeof
运算符或一元&
运算符的操作数,否则类型为“函数返回类型”的函数指示符将转换为类型为“指向函数返回类型的指针”的表达式
其结果是:
- 在
中,&foo
取&
的地址,因此foo
是&foo
的地址foo
- 在
中,函数指示符自动转换为函数的地址,因此foo
是foo
&foo
- 在
中,函数指示符自动转换为函数的地址。然后,*foo
运算符将其转换回函数,从而生成函数指示符。然后自动转换再次发生,函数指示符被转换回函数的地址,因此*
的结果是*foo
&foo
函数(参数列表…
表示法,函数实际上必须是指向函数的指针。因此,您可以使用(&foo)(参数…
)调用foo
。自动转换简化了语法,因此您可以编写foo(arguments…
),但调用表达式实际上需要函数的地址,而不是函数指示符
顺便说一下:
size\u t
值的合适printf
说明符是%zx
,而不是%lx
- 如果包含
,它将定义一种用于将指针转换为整数的类型,uintptpr\t
。最好将指针转换为size\t
函数foo
可隐式转换为指向函数foo
的指针
应用于函数的一元&
生成指向函数的指针,就像应用于变量时生成变量的地址一样
应用于函数指针的一元*
生成指向函数,就像应用于指向变量的普通指针时生成指向变量一样
所以这里,foo
与&foo
相同,后者与*foo
相同
因此*foo
与*(&foo)
相同,后者与foo
函数名(sysmbol)实际上是它自身的内存地址。当链接可执行文件时,可以用内存地址更改函数名。像call foo
这样的CPU指令是跳转到foo
函数CPU机构(代码)所在的RAM块。
arg = 0
arg = 0
arg = 0
&foo = 55eeef54c720
foo = 55eeef54c720
*foo = 55eeef54c720