简体   繁体   中英

Cast void pointer to struct and move it given size

I got a binary file that contains 3 different structs which I'm suppose to read to my program. After I have read the first struct I store its size, and then I'm suppose to convert my void pointer + the first structs length to a struct ip_hdr * (which is the second struct) and then read all it's values.

But the problems is I don't understand how you move a void pointer. I have understood that the void pointers don't have the same arithmetic rules as like a int pointer.

I want to do something like this:

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

But that doesn't work instead I get following error message:

Expression must be a pointer to a complete object type

Here is my code:

#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;
}

I now it's broken but I'm not done with it. Just need help with the pointers for now.

Here's an example of moving along an array of structures using a pointer to void .

The compiler doesn't know the type of object pointed to by a void* pointer. So you have two choices. One is to convert it to a pointer to the 'correct' type and then add the number of elements you want to move. The other is to add the number of bytes you want to an unsigned char* (or similar).

The action happens on the lines marked [1] and [2] below.

#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;
}

Typical output:

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

The actual values may vary.

Caveat

If I understand the question, the requirement is to move through a number of different struct s read together. That may be problematic because of alignment. It's beyond the scope of this question to go into detail but C may place or require padding between members or objects of different type to ensure they are aligned on the architecture. It's very common for example for 4 byte integers to lie on memory addresses that numerically divide by 4. That simplifies hardware and improves performance.

It's not clear from the fragment provided that the objects read in will be aligned and further copying of data and shuffling may be required.

That may have been taken into account but that can't be seen from the information provided.

What may help is the often overlooked offsetof(,) macro defined in stddef.h .

That returns the offset of a member within a type (taking internal padding into consideration). For example there is in general no guarantee (above) that:

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

This should work, assuming the structure is compatible with whatever is in the file (in general saving structs "raw" to disk is a bad idea, the exact layout of a struct in memory is compiler-dependent and not stable enough to use as a file format):

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

This adds "1" to a pointer of type ethernet_hdr , which will advance the actual pointer value by whatever size the Ethernet header structure has. The result is then cast to struct ip_hdr * .

I think this is what you wanted to do. You can do it by adding bytes to a char * , but what's the point?

You can't add directly to the void pointer, since pointer arithmetic is always in units of whatever is pointed at, and void has no size.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM