函数地址转换为char数组

时间:2015-05-18 12:44:09

标签: c function casting memcpy

为了我的教育目的,我想知道是否有一种替代方法,使用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;
}

感谢。

3 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:0)

  

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

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

你好像说你想要的是一个包含函数指针值的字节的char数组(而不是指针所指向的字节)。你可以通过几种方式获得它或类似的东西。最简单的方法是为指针的值创建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()相应的参数是对象指针。 C在对象指针和函数指针之间进行了区分,并没有定义在这两个类型系列的值之间进行转换的任何行为。我包括一个明确表达这种转换的演员(这可能使编译器能够注意和抱怨);您的代码会导致隐式执行此类转换。

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

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

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

    /* ... */    
}

那个人使用memcpy(),就像你问的那样。

无论如何,不​​需要工会。实际上,虽然基于联合的方法可能适用于您的C实现,但是从最近编写的不同联合成员读取正式表示未定义的行为。

答案 2 :(得分:0)

您正在做的是正式的未定义行为。 C语言表示联合可以包含任何不同的变量,但是您只能访问在联合中设置的变量:联合的大小足以包含其最大的成员。 at的值 大多数成员可以随时存储在union对象中。(参考: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");