转换为 char 数组的函数地址

function address cast to char array

为了我的教育目的,我想知道是否有 memcpy() 的替代方法来将函数地址转换为字符数组的以下代码?

#include <stdio.h>
#include <string.h>
typedef void (*_vfp)(void);
#define FPSZ sizeof(_vfp)


union rcast {
    _vfp fp;
    char fp_c[FPSZ];
} rc;
void a(void){
    printf("a()\n");
}

int main(int argc, char **argv)
{
    int i=0;
    memset(&rc,0,FPSZ);

    rc.fp=a;
    for (i=0;i<FPSZ;++i)
    printf("%hhx ",rc.fp_c[FPSZ-i-1]);  
    puts("");
    printf("%p\n",a);
    return 0;
}

谢谢。

对代码进行最少的修改:

#include <stdio.h>
#include <string.h>
typedef void (*_vfp)(void);
#define FPSZ sizeof(_vfp)

void a(void){
    printf("a()\n");
}

int main(int argc, char **argv)
{
    int i=0;
    _vfp fp = a;
    char fp_c[FPSZ];
    memcpy(fp_c, &fp, FPSZ);
    for (i=0;i<FPSZ;++i)
    printf("%hhx ",fp_c[FPSZ-i-1]);  
    puts("");
    printf("%p\n",a);
    return 0;
}

编辑:作为对评论的回应,这里有一个没有代理和 memcpy 的版本

#include <stdio.h>
#include <stdint.h>
#include <limits.h>
#include <string.h>
typedef void (*_vfp)(void);
#define FPSZ sizeof(_vfp)

void a(void){
    printf("a()\n");
}

int main(int argc, char **argv)
{
    int i=0;
    char fp_c[FPSZ];
    for (i=0;i<FPSZ;++i)
    fp_c[i] = (char) (((uintptr_t) &a) >> CHAR_BIT * i);
    for (i=0;i<FPSZ;++i)
    printf("%hhx ",fp_c[FPSZ-i-1]);  
    puts("");
    printf("%p\n",a);
    return 0;
}

For my educational purposes I was wondering if there is an alternative way with memcpy() to the following code for the function address casting to an array of chars?

请注意:虽然数组和指针密切相关,但它们是截然不同的东西。在许多其他差异中,您可以在强制转换运算符中使用指针类型,并将指针用作强制转换操作数,但您不能在这些上下文中使用数组类型或数组。

你似乎在说你想要的是一个包含函数指针值字节的字符数组(而不是指针指向的字节)。您可以通过多种方式获得它或类似的东西。最简单的方法是创建指向指针值的 char * 。同样,这 不是 数组,但它可以以许多与数组相同的方式使用:

typedef void (*_vfp)(void);

int main(int argc, char **argv)
{
    int i;
    _vfp fp = a;
    char *cp = &fp;

    for (i = 0; i < sizeof(fp); ++i) {
        printf("%hhx ", cp[i]);
    }
    printf("\n%p\n", (void *) a);
    return 0;
}

但是请注意,上面的代码表现出未定义的行为。 %p 字段描述符告诉 printf() 相应的参数是一个 object 指针。 C 区分了对象指针和函数指针,并且没有定义任何在这两种类型族的值之间进行转换的行为。我包括一个明确表达这种转换的转换(这可能使编译器注意到并抱怨);您的代码导致隐式执行此类转换。

如果你想要一个单独的数组对象包含指针值的字节(而不是指向函数的值),那么你可以用类似的方式得到它:

int main(int argc, char **argv)
{
    _vfp fp = a;
    char array[sizeof(fp)];

    memcpy(array, &fp, sizeof(array));

    /* ... */    
}

那个使用 memcpy(),完全按照你的要求。

不管怎么说,都没有工会的必要。事实上,尽管您的基于联合的方法可能碰巧适用于您的 C 实现,但从与最近写入的不同联合成员读取正式展示未定义的行为。

你正在做的是正式的未定义行为。 C 语言说联合可以包含任何不同的变量,但您只能访问在联合中设置的变量:联合的大小足以包含其最大的成员。在的值 大多数成员可以随时存储在联合对象中。(参考:C 语言规范草案 - 6.7.2.1 结构和联合说明符 - 16)

因此,它与通过 void 进行指针转换既不是最好也不是更差:

intptr_t ip = (intptr_t) &a;
char *fp_c = (void *) &intptr_t;

memcpy :

char fp_c[FPSZ];
intptr_t ip = (intptr_t) &a;
memcpy(fp_c, &ip, sizeof(intptr_t));

所有人都会给你相同的结果:

for (i=0; i<FPSZ; i++) {
    printf("%hhx ",fp_c[FPSZ-i-1]);
}
fputs("\n");