在运行时永久转换void指针

时间:2014-06-12 13:25:34

标签: c pointers casting void

我遇到的情况是,在运行时我不知道结构成员的类型。读取一个文件,该文件包含有关struct成员数据类型的信息(稍后将对其进行初始化)。

我想知道是否有办法在运行时将void指针永久转换为另一种类型。我认为类型可以用另一种方式表示(例如存储包含该类型的字符串)。但这会为正确访问void *带来很多开销(每个潜在类型的if语句)。

有任何想法或其他信息吗?

感谢。

2 个答案:

答案 0 :(得分:2)

我们认为您的文件格式如下

offset 1: count of elements
offset 2: size of the 1st element
offset 2+1: size of 2nd element
...
offset 2+count-1: size of the last element

offset 2+count: content of 1st element
offset 2+count+size of 1st elem: content of 2nd element
...

并且考虑到你有一个包含3个元素的文件:

1st elem: 
    size = 2 bytes
    content = 0x3412
2nd elem:
    size = 1 byte
    content = 0xAB
3rd elem:
    size = 5 bytes
    content = "Hell" (null terminated)

接下来是一个C程序,它创建这样一个文件然后解释它。函数readFile将适用于任何与前面描述的格式相关的文件。

警告:这只是可以做些什么的一个例子。请注意,未释放分配的内存,也未检查I / O操作!

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
struct Elem{
    int size;
    void *content;
};

struct List{
    int count;
    struct Elem *elems;
};

struct List *list;

void createFile(char *name)
{
    FILE *f;
    char buf[50];
    buf[0] = 3; /* nb elems */
    buf[1] = 2; /* size of elem 1 */
    buf[2] = 1; /* size of elem 2 */
    buf[3] = 5; /* size of elem 3 */
    /* elem 1 */
    buf[4] = 0x12;
    buf[5] = 0x34;
    /* elem 2 */
    buf[6] = 0xab;
    /* elem 3 */
    buf[7] = 'H';
    buf[8] = 'e';
    buf[9] = 'l';
    buf[10] = 'l';
    buf[11] = '\0';
    f = fopen(name, "wb");
    fwrite(buf, 12, 1, f);
    fclose(f);
}

void readFile(char *name)
{
    FILE *f;
    char c;
    int i;
    f = fopen(name, "rb");
    /* read number of elements */
    fread(&c, 1, 1, f);
    list->count = c;
    list->elems = (struct Elem*)malloc(sizeof(struct Elem) * c); /* allocate the needed size */
    for(i = 0; i < list->count; i++)
    {
        /* read the size of current element's size */
        fread(&c, 1, 1, f);
        list->elems[i].size = c;
        list->elems[i].content = malloc(c); /* allocate the needed size */
    }
    for(i = 0; i < list->count; i++)
    {
        /* read the current element's content */
        fread(list->elems[i].content, list->elems[i].size, 1, f);
    }
    fclose(f);
}

int main(int argc, char **argv)
{
    createFile("test");
    list = (struct List *)malloc(sizeof(struct List));
    readFile("test");
    printf("elem 1: %04X\n", *((unsigned short*)list->elems[0].content));
    printf("elem 2: %02X\n", *((unsigned char*)list->elems[1].content));
    printf("elem 3: %s\n\n", (char*)list->elems[2].content);
    /* you should free the allocated memory */
    return 0;
}    

结果输出为:

elem 1: 3412
elem 2: AB
elem 3: Hell

结构的填充方式如下:

list -> count = 3
        elems[0]-> size = 2
                   content = 0x3412
        elems[1]-> size = 1
                   content = 0xAB
        elems[2]-> size = 5
                   content = {'H', 'e', 'l', 'l', 0}

注意:

您可能已经注意到,将unsigned short转换为保存为序列{0x12, 0x34}的元素具有16位值0x3421。这是因为我的计算机的小端架构在较低地址(see)中存储了较不重要的字节。

答案 1 :(得分:0)

这在C中是不可能的,因为你在编译时不知道运行时的永久转换应该是什么。

(使用C ++,您可以使用静态或动态多态来执行某些操作。)