读取函数指针变量值

时间:2019-08-28 12:40:12

标签: c function-pointers

我对读取函数指针变量的值有些困惑。

#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

2 个答案:

答案 0 :(得分:2)

cat.sound()调用cat.sound所指向的函数并返回其返回值,该返回值是指向字符串文字char*开头的"meow"指针。用%s打印可以很好地得到预期的结果meow。用%x打印它可以实现实现定义的文字或未定义行为的地址表示。最好改用%p,这样可以消除出现不确定行为的可能性。

*cat.sound()取消指向字符串文字"meow"的第一个字符的指针,因此给出了'm'将直接打印的字符%c,而%x将格式化为十六进制(ascii)表示形式并打印出来。

cat.sound是一个函数的指针,用%s打印它是未定义的行为。实际上,正如您的输出所示,编译器选择打印位于指针地址处的函数的目标代码,直到遇到空字节为止。

*cat.soundcat.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()是指向该函数返回的数据的指针,因为括号()导致该函数被调用,并且结果是该函数返回的指针。