What's wrong with this code ? (struct serialization to raw memoryblock)

Discussion in 'C++' started by Alfonso Morra, Oct 3, 2005.

  1. Hi,

    I am at the end of my tether now - after spending several days trying to
    figure how to do this. I have finally written a simple "proof of
    concept" program to test serializing a structure containing pointers
    into a "flattened" bit stream.

    Here is my code (it dosen't work - compiles fine, pack appears to work,
    but unpack retrieves jibberish and causes program to crash).

    I would be grateful for any feedback that helps fix this. My intention
    is to build on this example, and use the ideas here, to be able to
    persist any data structure (I'll write different pack/unpack routines
    for different data stuctures, just to keep things simple). Anyway,
    here's the code:


    #include "stdlib.h"
    #include "stdio.h"
    #include "string.h"


    typedef struct {
    int l ;
    double d ;
    char* s; /* Null terminated string */
    } MyStruct ;


    void * pack(size_t *size, MyStruct* m);
    MyStruct *unpack(void* block);


    int main(int argc, char* argv[]) {

    MyStruct *in = (MyStruct*)malloc(sizeof(*in)), *out = NULL;
    unsigned char *memblock = NULL ;
    size_t size ;

    in->l = 1000 ;
    in->d = 3.142857;
    in->s = strdup("Simple Text" );

    memblock = (unsigned char*)pack(&size, in) ;
    out = unpack(memblock) ;

    printf("Int member has value : %d (expected : %d)", out->l, in->l ) ;
    printf("Double member has value : %f (expected : %f)", out->d, in->d ) ;
    printf("Int member has value : %s (expected : %s)", out->s, in->s ) ;

    free(in->s) ;
    free(in) ;
    free(out->s) ;
    free(out) ;

    }




    void * pack(size_t *size, MyStruct* m) {
    unsigned char *buff = NULL ;
    size_t len, length ;

    length = strlen(m->s) ;
    len = sizeof(int) + sizeof(double) + sizeof(size_t) +
    (length+1)*sizeof(char) ;
    buff = (unsigned char*)malloc(len) ;

    /*copy int*/
    memmove(buff, &(m->l), sizeof(int)) ;
    /*copy double*/
    memmove(buff + sizeof(int), &(m->d), sizeof(double)) ;
    /*store length of string*/
    memmove(buff + sizeof(int) + sizeof(int), &length, sizeof(size_t));
    /*copy string*/
    memmove(buff + sizeof(int) + sizeof(double), m->s,
    (length+1)*sizeof(char)) ;

    *size = len ;
    return buff ;
    }


    MyStruct *unpack(void* block) {
    int l, len ;
    double d ;
    char * s = NULL ;
    MyStruct *p = NULL ;

    /* get int*/
    memmove(&l, block, sizeof(int)) ;
    /* get double*/
    memmove(&d, (unsigned char*)block + sizeof(int), sizeof(double)) ;
    /* get string length*/
    memmove(&len, (unsigned char*)block + sizeof(int) + sizeof(double),
    sizeof(size_t)) ;
    /* get string*/
    s = (char*)malloc(len+1) ;
    memmove(s,(unsigned char*)block + sizeof(int) + sizeof(double)+
    sizeof(size_t),len) ;

    p = (MyStruct*)malloc(sizeof(*p)) ;

    p->l = l ;
    p->d = d ;
    p->s = s ;

    /* free resource */
    free(block) ;
    block = NULL ;
    return p ;
    }
    Alfonso Morra, Oct 3, 2005
    #1
    1. Advertising

  2. Alfonso Morra

    David Hilsee Guest

    Re: What's wrong with this code ? (struct serialization to raw memory block)

    "Alfonso Morra" <> wrote in message
    news:dhr7e9$668$-infra.bt.com...
    > Hi,
    >
    > I am at the end of my tether now - after spending several days trying to
    > figure how to do this. I have finally written a simple "proof of
    > concept" program to test serializing a structure containing pointers
    > into a "flattened" bit stream.
    >
    > Here is my code (it dosen't work - compiles fine, pack appears to work,
    > but unpack retrieves jibberish and causes program to crash).
    >
    > I would be grateful for any feedback that helps fix this. My intention
    > is to build on this example, and use the ideas here, to be able to
    > persist any data structure (I'll write different pack/unpack routines
    > for different data stuctures, just to keep things simple). Anyway,
    > here's the code:
    >
    >
    > #include "stdlib.h"
    > #include "stdio.h"
    > #include "string.h"
    >
    >
    > typedef struct {
    > int l ;
    > double d ;
    > char* s; /* Null terminated string */
    > } MyStruct ;
    >
    >
    > void * pack(size_t *size, MyStruct* m);
    > MyStruct *unpack(void* block);
    >
    >
    > int main(int argc, char* argv[]) {
    >
    > MyStruct *in = (MyStruct*)malloc(sizeof(*in)), *out = NULL;
    > unsigned char *memblock = NULL ;
    > size_t size ;
    >
    > in->l = 1000 ;
    > in->d = 3.142857;
    > in->s = strdup("Simple Text" );
    >
    > memblock = (unsigned char*)pack(&size, in) ;
    > out = unpack(memblock) ;
    >
    > printf("Int member has value : %d (expected : %d)", out->l, in->l ) ;
    > printf("Double member has value : %f (expected : %f)", out->d, in->d ) ;
    > printf("Int member has value : %s (expected : %s)", out->s, in->s ) ;
    >
    > free(in->s) ;
    > free(in) ;
    > free(out->s) ;
    > free(out) ;
    >
    > }
    >
    >
    >
    >
    > void * pack(size_t *size, MyStruct* m) {
    > unsigned char *buff = NULL ;
    > size_t len, length ;
    >
    > length = strlen(m->s) ;
    > len = sizeof(int) + sizeof(double) + sizeof(size_t) +
    > (length+1)*sizeof(char) ;
    > buff = (unsigned char*)malloc(len) ;
    >
    > /*copy int*/
    > memmove(buff, &(m->l), sizeof(int)) ;
    > /*copy double*/
    > memmove(buff + sizeof(int), &(m->d), sizeof(double)) ;
    > /*store length of string*/
    > memmove(buff + sizeof(int) + sizeof(int), &length, sizeof(size_t));


    memmove(buff + sizeof(int) + sizeof(double), &length, sizeof(size_t));

    > /*copy string*/
    > memmove(buff + sizeof(int) + sizeof(double), m->s,
    > (length+1)*sizeof(char)) ;


    memmove(buff + sizeof(int) + sizeof(double) + sizeof(size_t), m->s,
    (length+1)*sizeof(char)) ;

    > *size = len ;
    > return buff ;
    > }
    >
    >
    > MyStruct *unpack(void* block) {
    > int l, len ;
    > double d ;
    > char * s = NULL ;
    > MyStruct *p = NULL ;
    >
    > /* get int*/
    > memmove(&l, block, sizeof(int)) ;
    > /* get double*/
    > memmove(&d, (unsigned char*)block + sizeof(int), sizeof(double)) ;
    > /* get string length*/
    > memmove(&len, (unsigned char*)block + sizeof(int) + sizeof(double),
    > sizeof(size_t)) ;
    > /* get string*/
    > s = (char*)malloc(len+1) ;
    >
    > memmove(s,(unsigned char*)block + sizeof(int) + sizeof(double)+
    > sizeof(size_t),len) ;


    memmove(s,(unsigned char*)block + sizeof(int) + sizeof(double)+
    sizeof(size_t),len+1) ;

    > p = (MyStruct*)malloc(sizeof(*p)) ;
    >
    > p->l = l ;
    > p->d = d ;
    > p->s = s ;
    >
    > /* free resource */
    > free(block) ;
    > block = NULL ;
    > return p ;
    > }


    BTW, I don't see any reason to prefer memmove() to memcpy().

    --
    David Hilsee
    David Hilsee, Oct 3, 2005
    #2
    1. Advertising

  3. David Hilsee wrote:

    > "Alfonso Morra" <> wrote in message
    > news:dhr7e9$668$-infra.bt.com...
    >
    >>Hi,
    >>
    >>I am at the end of my tether now - after spending several days trying to
    >>figure how to do this. I have finally written a simple "proof of
    >>concept" program to test serializing a structure containing pointers
    >>into a "flattened" bit stream.
    >>
    >>Here is my code (it dosen't work - compiles fine, pack appears to work,
    >>but unpack retrieves jibberish and causes program to crash).
    >>
    >>I would be grateful for any feedback that helps fix this. My intention
    >>is to build on this example, and use the ideas here, to be able to
    >>persist any data structure (I'll write different pack/unpack routines
    >>for different data stuctures, just to keep things simple). Anyway,
    >>here's the code:
    >>
    >>
    >>#include "stdlib.h"
    >>#include "stdio.h"
    >>#include "string.h"
    >>
    >>
    >>typedef struct {
    >>int l ;
    >>double d ;
    >>char* s; /* Null terminated string */
    >>} MyStruct ;
    >>
    >>
    >>void * pack(size_t *size, MyStruct* m);
    >>MyStruct *unpack(void* block);
    >>
    >>
    >>int main(int argc, char* argv[]) {
    >>
    >>MyStruct *in = (MyStruct*)malloc(sizeof(*in)), *out = NULL;
    >>unsigned char *memblock = NULL ;
    >>size_t size ;
    >>
    >>in->l = 1000 ;
    >>in->d = 3.142857;
    >>in->s = strdup("Simple Text" );
    >>
    >>memblock = (unsigned char*)pack(&size, in) ;
    >>out = unpack(memblock) ;
    >>
    >>printf("Int member has value : %d (expected : %d)", out->l, in->l ) ;
    >>printf("Double member has value : %f (expected : %f)", out->d, in->d ) ;
    >>printf("Int member has value : %s (expected : %s)", out->s, in->s ) ;
    >>
    >>free(in->s) ;
    >>free(in) ;
    >>free(out->s) ;
    >>free(out) ;
    >>
    >>}
    >>
    >>
    >>
    >>
    >>void * pack(size_t *size, MyStruct* m) {
    >>unsigned char *buff = NULL ;
    >>size_t len, length ;
    >>
    >>length = strlen(m->s) ;
    >>len = sizeof(int) + sizeof(double) + sizeof(size_t) +
    >>(length+1)*sizeof(char) ;
    >>buff = (unsigned char*)malloc(len) ;
    >>
    >>/*copy int*/
    >>memmove(buff, &(m->l), sizeof(int)) ;
    >>/*copy double*/
    >>memmove(buff + sizeof(int), &(m->d), sizeof(double)) ;
    >>/*store length of string*/
    >>memmove(buff + sizeof(int) + sizeof(int), &length, sizeof(size_t));

    >
    >
    > memmove(buff + sizeof(int) + sizeof(double), &length, sizeof(size_t));
    >
    >
    >>/*copy string*/
    >>memmove(buff + sizeof(int) + sizeof(double), m->s,
    >>(length+1)*sizeof(char)) ;

    >
    >
    > memmove(buff + sizeof(int) + sizeof(double) + sizeof(size_t), m->s,
    > (length+1)*sizeof(char)) ;
    >
    >
    >>*size = len ;
    >>return buff ;
    >>}
    >>
    >>
    >>MyStruct *unpack(void* block) {
    >>int l, len ;
    >>double d ;
    >>char * s = NULL ;
    >>MyStruct *p = NULL ;
    >>
    >>/* get int*/
    >>memmove(&l, block, sizeof(int)) ;
    >>/* get double*/
    >>memmove(&d, (unsigned char*)block + sizeof(int), sizeof(double)) ;
    >>/* get string length*/
    >>memmove(&len, (unsigned char*)block + sizeof(int) + sizeof(double),
    >>sizeof(size_t)) ;
    >>/* get string*/
    >>s = (char*)malloc(len+1) ;
    >>
    >>memmove(s,(unsigned char*)block + sizeof(int) + sizeof(double)+
    >>sizeof(size_t),len) ;

    >
    >
    > memmove(s,(unsigned char*)block + sizeof(int) + sizeof(double)+
    > sizeof(size_t),len+1) ;
    >
    >
    >>p = (MyStruct*)malloc(sizeof(*p)) ;
    >>
    >>p->l = l ;
    >>p->d = d ;
    >>p->s = s ;
    >>
    >>/* free resource */
    >>free(block) ;
    >>block = NULL ;
    >>return p ;
    >>}

    >
    >
    > BTW, I don't see any reason to prefer memmove() to memcpy().
    >


    Many, many thanks David - your help is much appreciated !
    Alfonso Morra, Oct 3, 2005
    #3
  4. Alfonso Morra

    Greg Guest

    Re: What's wrong with this code ? (struct serialization to raw memory block)

    Alfonso Morra wrote:
    > Hi,
    >
    > I am at the end of my tether now - after spending several days trying to
    > figure how to do this. I have finally written a simple "proof of
    > concept" program to test serializing a structure containing pointers
    > into a "flattened" bit stream.
    >
    > Here is my code (it dosen't work - compiles fine, pack appears to work,
    > but unpack retrieves jibberish and causes program to crash).
    >
    > I would be grateful for any feedback that helps fix this. My intention
    > is to build on this example, and use the ideas here, to be able to
    > persist any data structure (I'll write different pack/unpack routines
    > for different data stuctures, just to keep things simple). Anyway,
    > here's the code:
    >
    >
    > #include "stdlib.h"
    > #include "stdio.h"
    > #include "string.h"
    >
    >
    > typedef struct {
    > int l ;
    > double d ;
    > char* s; /* Null terminated string */
    > } MyStruct ;
    >
    >
    > void * pack(size_t *size, MyStruct* m);
    > MyStruct *unpack(void* block);
    >
    >
    > int main(int argc, char* argv[]) {
    >
    > MyStruct *in = (MyStruct*)malloc(sizeof(*in)), *out = NULL;
    > unsigned char *memblock = NULL ;
    > size_t size ;
    >
    > in->l = 1000 ;
    > in->d = 3.142857;
    > in->s = strdup("Simple Text" );
    >
    > memblock = (unsigned char*)pack(&size, in) ;
    > out = unpack(memblock) ;
    >
    > printf("Int member has value : %d (expected : %d)", out->l, in->l ) ;
    > printf("Double member has value : %f (expected : %f)", out->d, in->d ) ;
    > printf("Int member has value : %s (expected : %s)", out->s, in->s ) ;
    >
    > free(in->s) ;
    > free(in) ;
    > free(out->s) ;
    > free(out) ;
    >
    > }
    >
    >
    >
    >
    > void * pack(size_t *size, MyStruct* m) {
    > unsigned char *buff = NULL ;
    > size_t len, length ;
    >
    > length = strlen(m->s) ;
    > len = sizeof(int) + sizeof(double) + sizeof(size_t) +
    > (length+1)*sizeof(char) ;
    > buff = (unsigned char*)malloc(len) ;
    >
    > /*copy int*/
    > memmove(buff, &(m->l), sizeof(int)) ;
    > /*copy double*/
    > memmove(buff + sizeof(int), &(m->d), sizeof(double)) ;
    > /*store length of string*/
    > memmove(buff + sizeof(int) + sizeof(int), &length, sizeof(size_t));
    > /*copy string*/
    > memmove(buff + sizeof(int) + sizeof(double), m->s,
    > (length+1)*sizeof(char)) ;
    >
    > *size = len ;
    > return buff ;
    > }
    >
    >
    > MyStruct *unpack(void* block) {
    > int l, len ;
    > double d ;
    > char * s = NULL ;
    > MyStruct *p = NULL ;
    >
    > /* get int*/
    > memmove(&l, block, sizeof(int)) ;
    > /* get double*/
    > memmove(&d, (unsigned char*)block + sizeof(int), sizeof(double)) ;
    > /* get string length*/
    > memmove(&len, (unsigned char*)block + sizeof(int) + sizeof(double),
    > sizeof(size_t)) ;
    > /* get string*/
    > s = (char*)malloc(len+1) ;
    > memmove(s,(unsigned char*)block + sizeof(int) + sizeof(double)+
    > sizeof(size_t),len) ;
    >
    > p = (MyStruct*)malloc(sizeof(*p)) ;
    >
    > p->l = l ;
    > p->d = d ;
    > p->s = s ;
    >
    > /* free resource */
    > free(block) ;
    > block = NULL ;
    > return p ;
    > }


    The members of a struct are not necessarily packed into the smallest
    space that will hold them. Usually the compiler will place the
    larger-sized elements at 4 or 8 or even 16 byte offsets and insert
    bytes to "pad" the space between fields of a struct if necessary. Using
    "sizeof" to calculate the field offsets is not reliable or likely even
    to be correct. There is an "offset" macro that will report the actual
    offset of a field in a struct by substracting the address of the struct
    from the address of the field. But then the routine to unpack the data
    must be compiled with the same alignment settings as the program that
    packed the data, and that is not a safe assumption to make either.

    Alternately, you just use a BER (ASN.1) library to encode the data. And
    then there is always XML to encode the data in a very portable format.

    Greg
    Greg, Oct 3, 2005
    #4
  5. Greg wrote:

    >
    >
    > The members of a struct are not necessarily packed into the smallest
    > space that will hold them. Usually the compiler will place the
    > larger-sized elements at 4 or 8 or even 16 byte offsets and insert
    > bytes to "pad" the space between fields of a struct if necessary. Using
    > "sizeof" to calculate the field offsets is not reliable or likely even
    > to be correct. There is an "offset" macro that will report the actual
    > offset of a field in a struct by substracting the address of the struct
    > from the address of the field. But then the routine to unpack the data
    > must be compiled with the same alignment settings as the program that
    > packed the data, and that is not a safe assumption to make either.
    >
    > Alternately, you just use a BER (ASN.1) library to encode the data. And
    > then there is always XML to encode the data in a very portable format.
    >
    > Greg
    >


    Ok, now you've got me worried ... :-(

    I can't use XML. Could you please shed some light on BER (never heard of
    it) and offset. How would you modify the code (just a couple of lines to
    show the concept) to use the more correct offset macro ?

    thanks
    Alfonso Morra, Oct 3, 2005
    #5
  6. Re: What's wrong with this code ? (struct serialization to raw memory block)

    On Mon, 3 Oct 2005 12:16:09 +0000 (UTC), Alfonso Morra
    <> wrote:

    >Hi,
    >
    >I am at the end of my tether now - after spending several days trying to
    >figure how to do this. I have finally written a simple "proof of
    >concept" program to test serializing a structure containing pointers
    >into a "flattened" bit stream.
    >
    >Here is my code (it dosen't work - compiles fine, pack appears to work,
    >but unpack retrieves jibberish and causes program to crash).
    >
    >I would be grateful for any feedback that helps fix this. My intention
    >is to build on this example, and use the ideas here, to be able to
    >persist any data structure (I'll write different pack/unpack routines
    >for different data stuctures, just to keep things simple). Anyway,
    >here's the code:
    >
    >
    >#include "stdlib.h"
    >#include "stdio.h"
    >#include "string.h"


    First of all, you have posted this to comp.lang.c++, so you should get
    used to doing things the C++ way:

    #include <cstdlib>
    #include <cstdio>
    #include <string>

    >typedef struct {
    > int l ;
    > double d ;
    > char* s; /* Null terminated string */
    >} MyStruct ;


    struct MyStruct {
    int l ; // terrible names of variables here...
    double d ;
    const char* s; /* Null terminated string */
    };

    I think I'll post this "as is" and try to do a rewrite in C++. Once
    you see the difference, I think you won't go back to using malloc and
    free ever again.

    --
    Bob Hairgrove
    Bob Hairgrove, Oct 3, 2005
    #6
  7. Alfonso Morra

    mlimber Guest

    Re: What's wrong with this code ? (struct serialization to raw memory block)

    Bob Hairgrove wrote:
    > First of all, you have posted this to comp.lang.c++, so you should get
    > used to doing things the C++ way:

    [snip]

    The program is very much C-style, not C++. The latter would ordinarily
    much prefer std::string to a char*. Check out these FAQs for more on
    C++-style serialization:

    http://www.parashift.com/c -faq-lite/serialization.html

    Cheers! --M
    mlimber, Oct 3, 2005
    #7
  8. Alfonso Morra

    Default User Guest

    Re: What's wrong with this code ? (struct serialization to raw memory block)

    Bob Hairgrove wrote:

    > On Mon, 3 Oct 2005 12:16:09 +0000 (UTC), Alfonso Morra
    > <> wrote:
    >
    > > Hi,
    > >
    > > I am at the end of my tether now - after spending several days
    > > trying to figure how to do this. I have finally written a simple
    > > "proof of concept" program to test serializing a structure
    > > containing pointers into a "flattened" bit stream.


    > First of all, you have posted this to comp.lang.c++, so you should get
    > used to doing things the C++ way:



    He's also been posting it to comp.lang.c. He's trying to come up with
    some sort of hybrid solution that works in either language. Others have
    pointed out the foolishness of that.




    Brian
    Default User, Oct 3, 2005
    #8
  9. Default User wrote:

    > Bob Hairgrove wrote:
    >
    >
    >>On Mon, 3 Oct 2005 12:16:09 +0000 (UTC), Alfonso Morra
    >><> wrote:
    >>
    >>
    >>>Hi,
    >>>
    >>>I am at the end of my tether now - after spending several days
    >>>trying to figure how to do this. I have finally written a simple
    >>>"proof of concept" program to test serializing a structure
    >>>containing pointers into a "flattened" bit stream.

    >
    >
    >>First of all, you have posted this to comp.lang.c++, so you should get
    >>used to doing things the C++ way:

    >
    >
    >
    > He's also been posting it to comp.lang.c. He's trying to come up with
    > some sort of hybrid solution that works in either language. Others have
    > pointed out the foolishness of that.
    >
    >
    >
    >
    > Brian


    You sir, are an idiot.
    Alfonso Morra, Oct 3, 2005
    #9
  10. Alfonso Morra

    Default User Guest

    Re: What's wrong with this code ? (struct serialization to raw memory block)

    Alfonso Morra wrote:



    > You sir, are an idiot.



    And you are plonked.




    Brian
    Default User, Oct 3, 2005
    #10
  11. Re: What's wrong with this code ? (struct serialization to raw memory block)

    On Mon, 03 Oct 2005 15:27:35 +0200, Bob Hairgrove
    <> wrote:

    >I think I'll post this "as is" and try to do a rewrite in C++. Once
    >you see the difference, I think you won't go back to using malloc and
    >free ever again.


    As promised. :) OK, below is my version. I tried not to change the
    basic structure of your program. It works; however, I would never
    write it this way because:

    (a) It is not (yet) exception-safe. However, it is a whole lot safer
    WRT memory management issues than using new and delete (or malloc and
    free);

    (b) It does way too little sanity-checking. However, using the STL
    containers such as std::string and std::vector make a lot of this
    unnecessary;

    (c) It is highly inflexible. Your pack() and unpack() functions make
    way too many assumptions about how MyStruct looks. Ideally, in C++,
    you let an object serialize and deserialize itself because only the
    object needs to know about its own structure. But you'll have to read
    up more about C++ and OOP first to grasp this.

    Look at how short the unpack() function has become. And we get along
    fine without a single new or delete -- anywhere!

    I haven't added any comments because most of the code now "speaks for
    itself". However, I'd be glad to comment later on any parts you might
    have questions about.

    //~~~~~ test_pack.cpp ~~~~~~~~~~~~~~~~
    // caveat: watch out for some line breaks

    #include <vector>
    #include <string>
    #include <iostream>
    #include <ostream>

    struct MyStruct {
    int l ;
    double d ;
    std::string s;
    };

    void pack(std::vector<char> &Memblock, MyStruct const &the_struct)
    {
    size_t block_len = sizeof(int)
    + sizeof(double)
    + the_struct.s.length()+1;
    size_t int_offset = sizeof(int);
    size_t dbl_offset = sizeof(int) + sizeof(double);

    if (!Memblock.empty()) Memblock.clear();
    Memblock.resize(block_len);

    int * pInt = reinterpret_cast<int*>(&Memblock[0]);
    double * pDbl = reinterpret_cast<double*>(&Memblock[int_offset]);
    char * pChar = &(Memblock[dbl_offset]);

    *pInt = the_struct.l;
    *pDbl = the_struct.d;
    strcpy(pChar, the_struct.s.c_str());
    }

    void unpack(MyStruct &the_struct, std::vector<char> const &block)
    {
    size_t int_offset = sizeof(int);
    size_t dbl_offset = sizeof(int) + sizeof(double);

    the_struct.l = *(reinterpret_cast<int const *>(&(block[0])));
    the_struct.d =
    *(reinterpret_cast<double const *>(&(block[int_offset])));
    the_struct.s = &(block[dbl_offset]);
    }

    int main() {

    using std::cout;
    using std::endl;

    MyStruct in, out;
    std::vector<char> memblock;

    in.l = 1000 ;
    in.d = 3.142857;
    in.s = "Simple Text";

    pack(memblock, in) ;
    unpack(out, memblock) ;

    cout << "Int member has value : " << out.l
    << " (expected : " << in.l << ")\n";
    cout << "Double member has value : " << out.d
    << " (expected : " << in.d << ")\n";
    cout << "String member has value : " << out.s
    << " (expected : " << in.s << ")\n";
    return 0;
    }

    --
    Bob Hairgrove
    Bob Hairgrove, Oct 4, 2005
    #11
  12. Re: What's wrong with this code ? (struct serialization to raw memory block)

    Also, note how the pack() and unpack() functions work independently of
    any quirks WRT struct member padding. We control the layout of the raw
    memory block, and the compiler takes care of the struct ... as it
    should be.

    When we cross the boundary with memmove() etc., we can get into
    trouble. But as you can see, it isn't necessary.

    --
    Bob Hairgrove
    Bob Hairgrove, Oct 4, 2005
    #12
  13. Bob Hairgrove wrote:

    > On Mon, 03 Oct 2005 15:27:35 +0200, Bob Hairgrove
    > <> wrote:
    >
    >
    >>I think I'll post this "as is" and try to do a rewrite in C++. Once
    >>you see the difference, I think you won't go back to using malloc and
    >>free ever again.

    >
    >
    > As promised. :) OK, below is my version. I tried not to change the
    > basic structure of your program. It works; however, I would never
    > write it this way because:
    >
    > (a) It is not (yet) exception-safe. However, it is a whole lot safer
    > WRT memory management issues than using new and delete (or malloc and
    > free);
    >
    > (b) It does way too little sanity-checking. However, using the STL
    > containers such as std::string and std::vector make a lot of this
    > unnecessary;
    >
    > (c) It is highly inflexible. Your pack() and unpack() functions make
    > way too many assumptions about how MyStruct looks. Ideally, in C++,
    > you let an object serialize and deserialize itself because only the
    > object needs to know about its own structure. But you'll have to read
    > up more about C++ and OOP first to grasp this.
    >
    > Look at how short the unpack() function has become. And we get along
    > fine without a single new or delete -- anywhere!
    >
    > I haven't added any comments because most of the code now "speaks for
    > itself". However, I'd be glad to comment later on any parts you might
    > have questions about.
    >
    > //~~~~~ test_pack.cpp ~~~~~~~~~~~~~~~~
    > // caveat: watch out for some line breaks
    >
    > #include <vector>
    > #include <string>
    > #include <iostream>
    > #include <ostream>
    >
    > struct MyStruct {
    > int l ;
    > double d ;
    > std::string s;
    > };
    >
    > void pack(std::vector<char> &Memblock, MyStruct const &the_struct)
    > {
    > size_t block_len = sizeof(int)
    > + sizeof(double)
    > + the_struct.s.length()+1;
    > size_t int_offset = sizeof(int);
    > size_t dbl_offset = sizeof(int) + sizeof(double);
    >
    > if (!Memblock.empty()) Memblock.clear();
    > Memblock.resize(block_len);
    >
    > int * pInt = reinterpret_cast<int*>(&Memblock[0]);
    > double * pDbl = reinterpret_cast<double*>(&Memblock[int_offset]);
    > char * pChar = &(Memblock[dbl_offset]);
    >
    > *pInt = the_struct.l;
    > *pDbl = the_struct.d;
    > strcpy(pChar, the_struct.s.c_str());
    > }
    >
    > void unpack(MyStruct &the_struct, std::vector<char> const &block)
    > {
    > size_t int_offset = sizeof(int);
    > size_t dbl_offset = sizeof(int) + sizeof(double);
    >
    > the_struct.l = *(reinterpret_cast<int const *>(&(block[0])));
    > the_struct.d =
    > *(reinterpret_cast<double const *>(&(block[int_offset])));
    > the_struct.s = &(block[dbl_offset]);
    > }
    >
    > int main() {
    >
    > using std::cout;
    > using std::endl;
    >
    > MyStruct in, out;
    > std::vector<char> memblock;
    >
    > in.l = 1000 ;
    > in.d = 3.142857;
    > in.s = "Simple Text";
    >
    > pack(memblock, in) ;
    > unpack(out, memblock) ;
    >
    > cout << "Int member has value : " << out.l
    > << " (expected : " << in.l << ")\n";
    > cout << "Double member has value : " << out.d
    > << " (expected : " << in.d << ")\n";
    > cout << "String member has value : " << out.s
    > << " (expected : " << in.s << ")\n";
    > return 0;
    > }
    >
    > --
    > Bob Hairgrove
    >



    Hi Bob,

    This is indeed very elegant. Thanks for your help/effort. I shall peruse
    through the code and add exception handling etc. I especially like the
    fact that not many asumptions are made about MyStruct - although I AM a
    little concerned about the liberal sprinkling of reinterpret casts ...

    very good nonetheless. Thanks
    Alfonso Morra, Oct 4, 2005
    #13
  14. Bob Hairgrove wrote:

    > On Mon, 03 Oct 2005 15:27:35 +0200, Bob Hairgrove
    > <> wrote:
    >
    >
    >>I think I'll post this "as is" and try to do a rewrite in C++. Once
    >>you see the difference, I think you won't go back to using malloc and
    >>free ever again.

    >
    >
    > As promised. :) OK, below is my version. I tried not to change the
    > basic structure of your program. It works; however, I would never
    > write it this way because:
    >
    > (a) It is not (yet) exception-safe. However, it is a whole lot safer
    > WRT memory management issues than using new and delete (or malloc and
    > free);
    >
    > (b) It does way too little sanity-checking. However, using the STL
    > containers such as std::string and std::vector make a lot of this
    > unnecessary;
    >
    > (c) It is highly inflexible. Your pack() and unpack() functions make
    > way too many assumptions about how MyStruct looks. Ideally, in C++,
    > you let an object serialize and deserialize itself because only the
    > object needs to know about its own structure. But you'll have to read
    > up more about C++ and OOP first to grasp this.
    >
    > Look at how short the unpack() function has become. And we get along
    > fine without a single new or delete -- anywhere!
    >
    > I haven't added any comments because most of the code now "speaks for
    > itself". However, I'd be glad to comment later on any parts you might
    > have questions about.
    >
    > //~~~~~ test_pack.cpp ~~~~~~~~~~~~~~~~
    > // caveat: watch out for some line breaks
    >
    > #include <vector>
    > #include <string>
    > #include <iostream>
    > #include <ostream>
    >
    > struct MyStruct {
    > int l ;
    > double d ;
    > std::string s;
    > };
    >
    > void pack(std::vector<char> &Memblock, MyStruct const &the_struct)
    > {
    > size_t block_len = sizeof(int)
    > + sizeof(double)
    > + the_struct.s.length()+1;
    > size_t int_offset = sizeof(int);
    > size_t dbl_offset = sizeof(int) + sizeof(double);
    >
    > if (!Memblock.empty()) Memblock.clear();
    > Memblock.resize(block_len);
    >
    > int * pInt = reinterpret_cast<int*>(&Memblock[0]);
    > double * pDbl = reinterpret_cast<double*>(&Memblock[int_offset]);
    > char * pChar = &(Memblock[dbl_offset]);
    >
    > *pInt = the_struct.l;
    > *pDbl = the_struct.d;
    > strcpy(pChar, the_struct.s.c_str());
    > }
    >
    > void unpack(MyStruct &the_struct, std::vector<char> const &block)
    > {
    > size_t int_offset = sizeof(int);
    > size_t dbl_offset = sizeof(int) + sizeof(double);
    >
    > the_struct.l = *(reinterpret_cast<int const *>(&(block[0])));
    > the_struct.d =
    > *(reinterpret_cast<double const *>(&(block[int_offset])));
    > the_struct.s = &(block[dbl_offset]);
    > }
    >
    > int main() {
    >
    > using std::cout;
    > using std::endl;
    >
    > MyStruct in, out;
    > std::vector<char> memblock;
    >
    > in.l = 1000 ;
    > in.d = 3.142857;
    > in.s = "Simple Text";
    >
    > pack(memblock, in) ;
    > unpack(out, memblock) ;
    >
    > cout << "Int member has value : " << out.l
    > << " (expected : " << in.l << ")\n";
    > cout << "Double member has value : " << out.d
    > << " (expected : " << in.d << ")\n";
    > cout << "String member has value : " << out.s
    > << " (expected : " << in.s << ")\n";
    > return 0;
    > }
    >
    > --
    > Bob Hairgrove
    >


    one last thing though - it may be better (safer) to use the offsetof
    macro to calculate the offsets - because of any padding that the
    compiler may have inserted, to align the struct fields.
    Alfonso Morra, Oct 4, 2005
    #14
  15. Re: What's wrong with this code ? (struct serialization to raw memory block)

    On Tue, 4 Oct 2005 09:50:49 +0000 (UTC), Alfonso Morra
    <> wrote:

    >one last thing though - it may be better (safer) to use the offsetof
    >macro to calculate the offsets - because of any padding that the
    >compiler may have inserted, to align the struct fields.


    I think you need to look at the code once more, and exactly what it
    does. There is absolutely no place in it at all where we need to know
    (or worry about) how the compiler puts a MyStruct in memory. The
    offsets are solely used BY US to place some binary bits in a raw
    memory buffer which has nothing to do with how the compiler aligns or
    pads anything. We read the data exactly the same way as we write it,
    but we use normal assignment operations to get it there and back.
    There is no memcpy() etc.

    sizeof(<whatever>), of course, will possibly be different on different
    platforms. This is where things like XML come in handy.

    --
    Bob Hairgrove
    Bob Hairgrove, Oct 4, 2005
    #15
  16. Re: What's wrong with this code ? (struct serialization to raw memory block)

    On Tue, 4 Oct 2005 09:47:45 +0000 (UTC), Alfonso Morra
    <> wrote:

    >I especially like the
    >fact that not many asumptions are made about MyStruct - although I AM a
    >little concerned about the liberal sprinkling of reinterpret casts ...


    Well, pack() and unpack() certainly DO make many assumtions about
    MyStruct. For example, if you change MyStruct and add a member, you'll
    have to re-write these functions -- both of them. You have a very
    tight dependency on it.

    As to reinterpret_cast, it is not much different than C-style casts
    which you seem to have no qualms about using, although they are
    potentially much more dangerous. If you need to cast between unrelated
    pointer types, as we do here, or pointers and int, use
    reinterpret_cast (with void pointers you can also use static_cast).
    There are situations where you just have to cast, espcially when doing
    things involving raw memory or wrapping legacy C code in C++ classes.

    The "shock and awe" <g> effect of seeing these long cast names is very
    effective because it is so easy to overlook a C-style cast when trying
    to maintain the code. And since it potentially involves more typing,
    it makes you try to find ways of doing things without resorting to a
    cast in the first place, thus resulting in improved code.

    I recommend you get Scott Meyers' books "Effective C++", "More
    Effective C++", and "Effective STL". They taught me more about C++
    programming than almost any other book with the possible exception of
    Stroustrup's "The C++ Programming Language". I find Scott Meyers'
    books easier to read, and the advice given is worth the book's weight
    in gold. He tells you pretty much all you need to know about casts in
    C++.

    After Meyers and Stroustrup, try Herb Sutter's excellent book
    "Exceptional C++". It deals with some fairly advanced concepts. At
    least for me, I was glad I had read the other books first. And for
    getting into template programming, nothing beats the book "C++
    Templates" by Josuttis and Vandevoorde.

    --
    Bob Hairgrove
    Bob Hairgrove, Oct 4, 2005
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Chris Fogelklou
    Replies:
    36
    Views:
    1,345
    Chris Fogelklou
    Apr 20, 2004
  2. Alfonso Morra

    serialization of structure into a raw memory block

    Alfonso Morra, Oct 1, 2005, in forum: C Programming
    Replies:
    5
    Views:
    498
    Michael Wojcik
    Oct 2, 2005
  3. Alfonso Morra
    Replies:
    11
    Views:
    443
    John Devereux
    Oct 3, 2005
  4. Alfonso Morra
    Replies:
    3
    Views:
    344
    grocery_stocker
    Oct 5, 2005
  5. Alfonso Morra
    Replies:
    9
    Views:
    341
Loading...

Share This Page