我对读取函数指针变量的值有些困惑。
#include <stdio.h>
char* cat_sound()
{
return "meow";
}
char* dog_sound()
{
return "hav";
}
typedef char* (*fptr_sound)(void);
typedef struct
{
int age;
fptr_sound sound;
}creature_t;
int main()
{
creature_t cat, dog;
cat.sound = cat_sound;
dog.sound = dog_sound;
printf("cat.sound()= %s, dog.sound()= %s\n", cat.sound(), dog.sound());
printf("cat.sound= %s, dog.sound= %s\n", cat.sound, dog.sound);
printf("*cat.sound= %s, *dog.sound= %s\n", *cat.sound, *dog.sound);
printf("*cat.sound()= %c, *dog.sound()= %c\n", *cat.sound(), *dog.sound());
printf("value of cat.sound= %x, dog.sound= %x\n", cat.sound, dog.sound);
printf("value of *cat.sound= %x, *dog.sound= %x\n", *cat.sound, *dog.sound);
printf("value of cat.sound()= %x, dog.sound()= %x\n", cat.sound(), dog.sound());
printf("value of *cat.sound()= %x, *dog.sound()= %x\n", *cat.sound(), *dog.sound());
return 0;
}
cat.sound()= meow, dog.sound()= hav
cat.sound= U▒▒]▒U▒▒]▒U▒▒S▒▒▒▒ ▒D$▒D$&▒D$▒ЉËD$▒Љ\▒D$▒$▒▒▒▒▒T$▒D$▒T▒D$▒$▒x▒▒▒▒T$▒D$▒T▒D$▒$<▒\▒▒▒▒D$▒▒▒, dog.sound= U▒▒]▒U▒▒S▒▒▒▒ ▒D$▒D$&▒D$▒ЉËD$▒Љ\▒D$▒$▒▒▒▒▒T$▒D$▒T▒D$▒$▒x▒▒▒▒T$▒D$▒T▒D$▒$<▒\▒▒▒▒D$▒▒▒
*cat.sound= U▒▒]▒U▒▒]▒U▒▒S▒▒▒▒ ▒D$▒D$&▒D$▒ЉËD$▒Љ\▒D$▒$▒▒▒▒▒T$▒D$▒T▒D$▒$▒x▒▒▒▒T$▒D$▒T▒D$▒$<▒\▒▒▒▒D$▒▒▒, *dog.sound= U▒▒]▒U▒▒S▒▒▒▒ ▒D$▒D$&▒D$▒ЉËD$▒Љ\▒D$▒$▒▒▒▒▒T$▒D$▒T▒D$▒$▒x▒▒▒▒T$▒D$▒T▒D$▒$<▒\▒▒▒▒D$▒▒▒
*cat.sound()= m, *dog.sound()= h
value of cat.sound= 804841c, dog.sound= 8048426
value of *cat.sound= 804841c, *dog.sound= 8048426
value of cat.sound()= 80485f0, dog.sound()= 80485f5
value of *cat.sound()= 6d, *dog.sound()= 68
如下所示,cat.sound保留cat_sound函数的地址。 那么* cat.sound为什么返回相同的值? (如果与整数指针进行比较,则取消引用将返回其指向的值,而不是值本身。)
为什么cat.sound()指向函数返回的值而不是函数地址本身?
08048430 <main>:
8048430: 55 push ebp
8048431: 89 e5 mov ebp,esp
8048433: 53 push ebx
8048434: 83 e4 f0 and esp,0xfffffff0
8048437: 83 ec 20 sub esp,0x20
804843a: c7 44 24 1c 1c 84 04 mov DWORD PTR [esp+0x1c],0x804841c
0804841c <cat_sound>:
804841c: 55 push ebp
804841d: 89 e5 mov ebp,esp
804841f: b8 f0 85 04 08 mov eax,0x80485f0
8048424: 5d pop ebp
8048425: c3 ret
08048426 <dog_sound>:
8048426: 55 push ebp
8048427: 89 e5 mov ebp,esp
8048429: b8 f5 85 04 08 mov eax,0x80485f5
804842e: 5d pop ebp
804842f: c3 ret
答案 0 :(得分:2)
cat.sound()
调用cat.sound
所指向的函数并返回其返回值,该返回值是指向字符串文字char*
开头的"meow"
指针。用%s
打印可以很好地得到预期的结果meow
。用%x
打印它可以实现实现定义的文字或未定义行为的地址表示。最好改用%p
,这样可以消除出现不确定行为的可能性。
*cat.sound()
取消指向字符串文字"meow"
的第一个字符的指针,因此给出了'm'
将直接打印的字符%c
,而%x
将格式化为十六进制(ascii)表示形式并打印出来。
cat.sound
是一个函数的指针,用%s
打印它是未定义的行为。实际上,正如您的输出所示,编译器选择打印位于指针地址处的函数的目标代码,直到遇到空字节为止。
*cat.sound
与cat.sound
相同。 *
应用于函数指针实际上没有任何作用。它产生一个功能指示符,然后您使用它的方式再次衰减为功能指针。这与非功能指针的行为不同。再次使用%s
打印它是未定义的行为。
使用%x
打印功能指针也是未定义的行为,有关如何合法打印功能指针的信息,请参见this question。
答案 1 :(得分:1)
像数组一样,功能指示符会自动转换为指向其功能的指针。 C 2018 6.3.2.1 4说:
功能指示符是具有功能类型的表达式。除非它是
sizeof
运算符或一元&
运算符的操作数,否则类型为“ function returning type ”的函数指示符将转换为具有类型的表达式“返回类型的函数指针”。
因此,编译器会自动将cat_sound
(作为函数的名称,指定函数)转换为&cat_sound
。
此外,由于cat.sound
是指向函数的指针,因此*cat.sound
指定函数。但是,由于它是一个函数指示符,因此它会自动转换为指向该函数的指针,并生成&*cat.sound
,它只是函数的地址,与cat.sound
相同。
cat.sound()
是指向该函数返回的数据的指针,因为括号()
导致该函数被调用,并且结果是该函数返回的指针。