Problem with structs and mem. allocation

Discussion in 'C++' started by Nafai, Sep 29, 2004.

  1. Nafai

    Nafai Guest

    Hi. Have a look at this program:

    struct tmp {
    short a;
    int b;
    short c;
    };

    int main()
    {
    ofstream f("tmp.bin",ios::binary);
    tmp t; t.a=5; t.b=2000; t.c=2;

    f.write((const char*)&t.a,sizeof(short));
    f.write((const char*)&t.b,sizeof(int));
    f.write((const char*)&t.c,sizeof(char));
    f.close();

    ifstream g("tmp.bin", ios::binary);
    tmp s;

    g.read((char*)&s,sizeof(tmp));

    cout << s.a << " " << s.b << " " << s.c << " " << endl;
    cout << &s.a << " " << &s.b << " " << &s.c << " " << endl;
    g.close();
    }

    The output should be (supposing &s==0x22fd48):

    5 2000 2
    0x22fd48 0x22fd4a 0x22fd4e

    But the actual output is:

    5 131072 -2764
    0x22fd48 0x22fd4c 0x22fd50

    So the problem is that the parts of the struct are not continuous in
    memory!!! I mean, s.b should start 2 bytes after &s but actually it starts
    after 4 bytes. That's why the g.read(...) doesn't work.

    I tried:

    but: cout << *((int*)((char*) (&s)+sizeof(short)))

    and it output 2000.

    In conclusion: &s+sizeof(s.a) != &s.b

    Is all this my mistake or am I right??? I'm looking forward to an
    explanation.

    Thanks!
     
    Nafai, Sep 29, 2004
    #1
    1. Advertising

  2. "Nafai" <> wrote in message
    news:1qx6d.2746753$...
    > Hi. Have a look at this program:
    >
    > struct tmp {
    > short a;
    > int b;
    > short c;
    > };
    >
    > int main()
    > {
    > ofstream f("tmp.bin",ios::binary);
    > tmp t; t.a=5; t.b=2000; t.c=2;
    >
    > f.write((const char*)&t.a,sizeof(short));
    > f.write((const char*)&t.b,sizeof(int));
    > f.write((const char*)&t.c,sizeof(char));
    > f.close();
    >
    > ifstream g("tmp.bin", ios::binary);
    > tmp s;
    >
    > g.read((char*)&s,sizeof(tmp));
    >
    > cout << s.a << " " << s.b << " " << s.c << " " << endl;
    > cout << &s.a << " " << &s.b << " " << &s.c << " " << endl;
    > g.close();
    > }
    >
    > The output should be (supposing &s==0x22fd48):
    >
    > 5 2000 2
    > 0x22fd48 0x22fd4a 0x22fd4e
    >
    > But the actual output is:
    >
    > 5 131072 -2764
    > 0x22fd48 0x22fd4c 0x22fd50
    >
    > So the problem is that the parts of the struct are not continuous in
    > memory!!! I mean, s.b should start 2 bytes after &s but actually it starts
    > after 4 bytes. That's why the g.read(...) doesn't work.


    Right. Now what made you think that they had to be contiguous in memory?

    >
    > I tried:
    >
    > but: cout << *((int*)((char*) (&s)+sizeof(short)))
    >
    > and it output 2000.
    >
    > In conclusion: &s+sizeof(s.a) != &s.b
    >
    > Is all this my mistake or am I right??? I'm looking forward to an
    > explanation.
    >


    Compilers are allowed to add 'padding' between the data members of a struct
    or class. They do this for efficiency reasons. Most compilers will have
    compiler specific options to alter the padding or to turn it off entirely.

    Alternatively you could read your data in the same way that you wrote it,
    that would be the sensible thing to do.

    john
     
    John Harrison, Sep 29, 2004
    #2
    1. Advertising

  3. Nafai

    Nafai Guest

    >>
    >> But the actual output is:
    >>
    >> 5 131072 -2764
    >> 0x22fd48 0x22fd4c 0x22fd50
    >>
    >> So the problem is that the parts of the struct are not continuous in
    >> memory!!! I mean, s.b should start 2 bytes after &s but actually it
    >> starts
    >> after 4 bytes. That's why the g.read(...) doesn't work.

    >
    > Right. Now what made you think that they had to be contiguous in memory?
    >


    I have seen most times things like g.read((char*)&s,sizeof(tmp)); to read a
    full struct with one instruction.
     
    Nafai, Sep 29, 2004
    #3
  4. "Nafai" <> wrote in message
    news:EZx6d.2747263$...
    > >>
    > >> But the actual output is:
    > >>
    > >> 5 131072 -2764
    > >> 0x22fd48 0x22fd4c 0x22fd50
    > >>
    > >> So the problem is that the parts of the struct are not continuous in
    > >> memory!!! I mean, s.b should start 2 bytes after &s but actually it
    > >> starts
    > >> after 4 bytes. That's why the g.read(...) doesn't work.

    > >
    > > Right. Now what made you think that they had to be contiguous in memory?
    > >

    >
    > I have seen most times things like g.read((char*)&s,sizeof(tmp)); to read

    a
    > full struct with one instruction.
    >


    That code is OK providing that you read and write in the same way. Your
    mistake was reading one way and writing another. Providing you don't mind
    any padding bytes being written out to the file, you can read and write a
    whole struct in one go.

    And of course any binary read or write is not portable across machines,
    compilers, etc. etc.

    john
     
    John Harrison, Sep 29, 2004
    #4
  5. Nafai wrote:
    >
    > >>
    > >> But the actual output is:
    > >>
    > >> 5 131072 -2764
    > >> 0x22fd48 0x22fd4c 0x22fd50
    > >>
    > >> So the problem is that the parts of the struct are not continuous in
    > >> memory!!! I mean, s.b should start 2 bytes after &s but actually it
    > >> starts
    > >> after 4 bytes. That's why the g.read(...) doesn't work.

    > >
    > > Right. Now what made you think that they had to be contiguous in memory?
    > >

    >
    > I have seen most times things like g.read((char*)&s,sizeof(tmp)); to read a
    > full struct with one instruction.


    Right. Now search the same program and you will find that those programs
    also write a struct in one rush

    g.write( char*)&s, sizeof(tmp) );

    and *never* by writing each struct member individually.
    (Except of course when the programmer was aware of the padding issue
    and took it into account. But thats rare).

    --
    Karl Heinz Buchegger
     
    Karl Heinz Buchegger, Sep 29, 2004
    #5
  6. Nafai

    Nafai Guest

    I came across this problem when reading a BMP file. I defined a struct for
    the header and I got into trouble when reading the whole struct. So I have
    to read each element of the header (more than 20) one by one? Isn't there
    any easier way?


    "Karl Heinz Buchegger" <> escribió en el mensaje
    news:...
    > Nafai wrote:
    >>
    >> >>
    >> >> But the actual output is:
    >> >>
    >> >> 5 131072 -2764
    >> >> 0x22fd48 0x22fd4c 0x22fd50
    >> >>
    >> >> So the problem is that the parts of the struct are not continuous in
    >> >> memory!!! I mean, s.b should start 2 bytes after &s but actually it
    >> >> starts
    >> >> after 4 bytes. That's why the g.read(...) doesn't work.
    >> >
    >> > Right. Now what made you think that they had to be contiguous in
    >> > memory?
    >> >

    >>
    >> I have seen most times things like g.read((char*)&s,sizeof(tmp)); to read
    >> a
    >> full struct with one instruction.

    >
    > Right. Now search the same program and you will find that those programs
    > also write a struct in one rush
    >
    > g.write( char*)&s, sizeof(tmp) );
    >
    > and *never* by writing each struct member individually.
    > (Except of course when the programmer was aware of the padding issue
    > and took it into account. But thats rare).
    >
    > --
    > Karl Heinz Buchegger
    >
     
    Nafai, Sep 29, 2004
    #6
  7. Nafai wrote:

    > I came across this problem when reading a BMP file. I defined a struct for
    > the header and I got into trouble when reading the whole struct. So I have
    > to read each element of the header (more than 20) one by one? Isn't there
    > any easier way?


    Write a file that describes the format of the header, and write a program
    that reads this file and generates the code for reading the header.

    Of course is more work, but is reusable.

    --
    Salu2
     
    =?ISO-8859-15?Q?Juli=E1n?= Albo, Sep 29, 2004
    #7
  8. "Nafai" <> wrote in message
    news:zrD6d.2753335$...
    >I came across this problem when reading a BMP file. I defined a struct for
    >the header and I got into trouble when reading the whole struct. So I have
    >to read each element of the header (more than 20) one by one? Isn't there
    >any easier way?
    >


    Well to be strictly portable you have to read the file one byte at a time,
    not just one field at a time. How do you know that the format of an integer
    in the BMP file (say) corresponds to the format of an int in your compiler?

    If you don't mind not being portable then you should look at compiler
    options or pragmas that will allow you to control the padding in your
    struct. Then you can read the whole struct in one go.

    john
     
    John Harrison, Sep 29, 2004
    #8
    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. Yossarian

    Pointer to Pointer & Mem allocation

    Yossarian, Jun 7, 2004, in forum: C Programming
    Replies:
    2
    Views:
    3,675
    Mike Wahler
    Jun 7, 2004
  2. srini

    Dynamic mem allocation for pointers

    srini, Dec 14, 2005, in forum: C Programming
    Replies:
    4
    Views:
    358
    Barry Schwarz
    Dec 18, 2005
  3. Replies:
    8
    Views:
    317
    jaysome
    Mar 1, 2007
  4. news.aon.at
    Replies:
    11
    Views:
    649
    Ian Collins
    Jan 29, 2011
  5. Durango

    problem with memory allocation and structs

    Durango, Dec 4, 2011, in forum: C Programming
    Replies:
    5
    Views:
    337
    Durango
    Dec 9, 2011
Loading...

Share This Page