【问题标题】:Cast void pointer to struct and move it given size将 void 指针转换为结构并将其移动给定大小
【发布时间】:2018-06-01 19:39:27
【问题描述】:

我得到了一个包含 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;
}

我现在它坏了,但我还没有完成它。现在只需要指针方面的帮助。

【问题讨论】:

  • 请不要描述您的代码,但要显示它。
  • 但这行不通。 解释不多!此外,您在ptr = (struct ip_hdr *)ptr) + (sizeOfFirstStruct)); 中缺少括号( 请发布您的代码。
  • @Gaurav 那我该怎么做呢?我应该先将指针投射到结构 Ip_hdr 然后移动它还是可以使用 fseek 之类的函数以某种方式移动它?
  • 您发布的代码中的ptr = (struct ip_hdr *)ptr) + (sizeOfFirstStruct)); 在哪里?
  • ptr = (struct ip_hdr *)ptr) + (sizeOfFirstStruct));错了,请确认确实是ptr = ((struct ip_hdr *)ptr) + sizeOf(FirstStruct);。永远不要重新输入有问题的代码,而是复制/粘贴它。

标签: c struct void-pointers


【解决方案1】:

这应该可以工作,假设结构与文件中的任何内容兼容(通常将结构“原始”保存到磁盘是一个坏主意,内存中结构的确切布局取决于编译器并且不够稳定用作文件格式):

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

这会将“1”添加到ethernet_hdr 类型的指针上,这将使实际指针值前进以太网标头结构具有的任何大小。然后将结果转换为struct ip_hdr *

我认为这就是你想要做的。您可以通过将字节添加到 char * 来做到这一点,但有什么意义呢?

您不能直接添加到 void 指针,因为指针运算总是以所指向的任何单位为单位,而 void 没有大小。

【讨论】:

  • 我会立即尝试。我想这样做的原因是因为我想读取每个结构的大小,然后访问位于最后一个结构之后的文本消息。所以我想工作获取结构的大小,将我的 void 指针转换为下一个结构,并将它的大小增加前一个结构的大小,直到我到达末尾。不确定您是否理解我要解释的内容。不,我知道算术规则不适用于 void 类型的指针
【解决方案2】:

这是一个使用指向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

实际值可能会有所不同。

警告

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

如果读入的对象将对齐并且可能需要进一步复制数据和改组,则从片段中不清楚。

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

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

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

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

【讨论】:

  • @PaulOgilvie:我猜你可能正在编译 C++ 而不是 C 标记。恕我直言,您可以在 void* 上进行指针运算这一事实是在 C++ 中整理的 C 类型系统的不一致。
  • 确实如此。这是 GNU C 中的一个坏习惯漏洞。
  • @PaulOgilvie 已修复。
  • 好的,谢谢您的回答。但是,如果我在二进制文件中有 3 个不同的结构,它们不像您的示例那样在数组中。您将 void 指针指向一个数组,我只是尝试使用 fread 来获取其中的第一个结构。如何将指针从第一个结构更改为下一个结构?如果我理解正确,您只需指向 thingy 数组中的下一个:thingy* nextthingy=((unsigned char*)voidptr)+sizeof(thingy);还是我理解错了?
  • 这就是我正在考虑的对齐方式。如果您将第一个结构读入ptr(您的代码),那么提前是sizeof(ethernet_hdr) 字节,它可能无法对齐以读取它之后的下一个结构。您可能最好将这三个都作为单独的读入单独的结构来阅读。您仍然需要知道根据编译器对齐成员的方式或您最终逐个成员读取成员,它们将在内部填充(或不填充)。
猜你喜欢
  • 2023-03-26
  • 2016-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-02-26
  • 2014-01-13
  • 2016-01-12
  • 2012-05-05
相关资源
最近更新 更多