tags:

views:

92

answers:

3

Is there a safer way to typecast data from a generic pointer.? More specifically , is there a way to check if the type casting is safe or not.

Suppose void*data we receive from the recv function in netwrking code.

Suppose there are two structures:

struct data1
{
int val;
double val1;
}

struct data2
{
char str[100];
long double val3;
}

Suppose we have the following receive call:

recv(int s, void *buf, size_t len, int flags);

and buf can be of type struct data1 or struct data2. Here are my questions:

  1. Can we perform some sort of check of which type is stored in buf?

  2. What happens if the following happens:

    // buf contains a message of type data1 
    
    
    struct data2 *d2; // assume its malloced too
    
    
    d2 = (struct data2)buf;
    
    
     d2->val3=3.145
    
+2  A: 

If you've serialized your data and sent it, all you've got now is raw bytes. There's no way to determine what type raw data is.

The only way to try and alleviate the issue is to create a standard way of communicating the type as well. Simple method:

enum possible_types
{
    t_data1 = 0,
    t_data2,
};

And send that first. The receiver can check what type it's suppose to be there.

GMan
Since t_data1 and t_data2 have the same value (zero), I'm not sure how to tell them apart... :D
Jonathan Leffler
Oops, hehe. Fixed. :P
GMan
+3  A: 

I believe you can do something like this (untested):

#include <stdio.h>

struct a {
    int ival;
    double dval;
};

struct b {
    char cval[20];
    long double ldval;
};

enum stype_ {
    TYPE_A,
    TYPE_B
};

struct combined {
    enum stype_ stype;
    union {
        struct a adata;
        struct b bdata;
    } u;
}

void f(void *data)
{
    struct combined *c = data;
    if (c->stype == TYPE_A) {
        struct a aa = c->u.adata;
    } else if (c->stype == TYPE_B) {
        struct b bb = c->u.bdata;
    } else {
        fprintf(stderr, "Invalid struct!\n");
    }   
}

int main(void)
{
    struct a a1 = { 0, 0 };
    struct b b1 = { "Hi", 0 };
    struct combined c;

    c.stype = TYPE_A;
    c.u.adata = a1;
    f(&c);

    c.stype = TYPE_B;
    c.u.bdata = b2;
    f(&c);

    return 0;
}

As you can see, you have to be careful to set the stype member to the correct value if you use this scheme.

Be careful sending such data over the network! In general, it's not safe or recommended to send structs raw over the network. Even if you're on the same kind of architecture, structure padding etc., can be different with different executables, compilers, etc. If you are on different machines, you might have to deal with endianness issues.

It's far better to serialize the data to bytes that you know exactly the contents of, and then decode them on the receiving side. If you do use such a scheme (highly recommended), you can encode the type of information in the first byte sent.

Alok
A: 

Check out Serialization—How to Pack Data and Son of Data Encapsulation.

We have to take care of endianess and type sizes when we transmit structures.
Simple type casting isn't enough always.

Nick D