将void指针转换为struct并将其移动给定大小

时间:2017-12-19 11:17:15

标签: c struct void-pointers

我有一个包含3种不同结构的二进制文件,我想这些结构可以读到我的程序。在我读完第一个结构后,我存储它的大小,然后我想将我的void指针+第一个结构长度转换为struct ip_hdr *(这是第二个结构),然后读取它的所有值。

但问题是我不明白你如何移动一个void指针。我知道void指针没有像int指针那样的算术规则。

我想做这样的事情:

ptr = (struct ip_hdr *)ptr) + (ethRes));

但是这不起作用而是我收到以下错误消息:

  

表达式必须是指向完整对象类型的指针

这是我的代码:

#pragma warning(disable: 4996)
#include <stdio.h>
#include <stdlib.h>
#include "framehdr.h"
#include <crtdbg.h>

int main()
{
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

    FILE *fileOpen = fopen("C:\\Users\\Viktor\\source\\repos\\Laboration_3\\Laboration_3\\TCPdump", "rb");


    //Pointers and variables
    struct ethernet_hdr eth;
    struct ethernet_hdr *ethPtr;
    struct ip_hdr ip;
    struct ip_hdr *ipPtr;
    struct tcp_hdr tcp;
    struct tcp_hdr *tcpPtr;

    if (fileOpen == NULL)
    {
        printf("Error\n");
    }
    else
    {
        printf("Success\n");
    }

    char ethrr[10];
    fscanf(fileOpen, "%s", ethrr);
    int length = atoi(ethrr);
    printf("Nr: %d\n", length);

    void *ptr;
    ptr = (void *)malloc(length);
    fread(ptr, sizeof(eth), 1, fileOpen);

    int ethRes = sizeof(((struct ethernet_hdr*)ptr)->dhost) +
        sizeof(((struct ethernet_hdr*)ptr)->shost) +
        sizeof(((struct ethernet_hdr*)ptr)->type);
    printf("%d\n", ethRes);
    printf("ptr1: %d\n", &ptr);

    system("pause");
    fclose(fileOpen);


    return 0;
}

我现在已经破了,但我没有完成它。现在只需要指点帮助。

2 个答案:

答案 0 :(得分:3)

这是使用指向void的指针移动结构数组的示例。

编译器不知道void*指针指向的对象类型。 所以你有两个选择。一种方法是将其转换为指向“正确”类型的指针,然后添加要移动的元素数。另一种是将所需的字节数添加到unsigned char*(或类似)。

行动发生在下面标有[1][2]的行上。

#include <stdio.h>

typedef struct {
    int payload;
    double other;
} thingy;

int main(void) {
    thingy athingy[2];//An array of two thingys.
    void* voidptr=athingy; //a pointer to first thingy.

    thingy* nextthingy=((unsigned char*)voidptr)+sizeof(thingy); //[A] next thingy points to second element of array.
    thingy* altnext=((thingy*)voidptr)+1; //[B] Points to the same thing!

    printf("voidptr==%p %zu\n",voidptr,sizeof(thingy));
    printf("nextthingy==%p\n",nextthingy);
    printf("altthingy==%p\n",altnext);

    if(nextthingy==altnext){
        printf("Same\n");
    }else{
        printf("Not same (oh dear)\n"); 
    }
    return 0;
}

典型输出:

voidptr==0x7ffd6909d660 4
nextthingy==0x7ffd6909d664
altthingy==0x7ffd6909d664
Same

实际值可能会有所不同。

<强>买者

如果我理解了这个问题,那么要求是将许多不同的struct一起阅读。 由于对齐,这可能是有问题的。详细讨论了这个问题的范围,但C可能会在成员或不同类型的对象之间放置或要求填充,以确保它们在架构上对齐。例如,4字节整数位于数字除以4的存储器地址上非常常见。这简化了硬件并提高了性能。

从提供的片段中不清楚读入的对象是否会对齐,可能需要进一步复制数据和改组。

这可能已被考虑在内,但从提供的信息中无法看出。

offsetof(,)中定义的经常被忽视的stddef.h宏可能有所帮助。

返回类型中成员的偏移量(考虑内部填充)。例如,通常不保证(上文):

voidptr+sizeof(payload)==((unsigned char*)voidptr)+offsetof(thingy,other)

答案 1 :(得分:2)

这应该有效,假设结构与文件中的任何内容兼容(通常保存结构&#34;原始&#34;到磁盘是一个坏主意,内存中结构的确切布局是依赖于编译器的并且不够稳定,无法用作文件格式):

const struct ip_hdr * const ip = (struct ip_hdr *) ((struct ethernet_hdr *) ptr + 1);

这增加了&#34; 1&#34;指向类型为ethernet_hdr的指针,它将按以太网报头结构的大小提前实际指针值。然后将结果转换为struct ip_hdr *

我认为这就是你想要做的。您可以通过向char *添加字节来实现,但重点是什么?

你不能直接添加到void指针,因为指针算术总是以指向的为单位,void没有大小。