Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Categories

Sizeof behaviour on classes

TheSpiderTheSpider Member Posts: 4
Using DEV-C++ ide on the cygwin compiler
[code]
#define DEBUG //Debug Mode enabled

const short int PATCHFILE = 21584; //this decodes to PT as short int.
//data storage classes
class patchheader //i dont like structures
{
public:
short int type; // should read "PT" in ascii to show file is Patch file
unsigned long filesize; //filesize in bytes
unsigned long firstpd; // location of first patchdata
};

//data storage classes
class patchheader //i dont like structures
{
public:
short int type; // should read "PT" in ascii to show file is Patch file
unsigned long filesize; //filesize in bytes
unsigned long firstpd; // location of first patchdata
};

long int createpatchfile(const char *ccfilename)
{
patchheader ph;
ph.filesize = sizeof(ph); //why is this 12?
ph.firstpd = sizeof(ph)+ 1;
ph.type = PATCHFILE;

ofstream ofsnew(ccfilename);
#ifdef DEBUG
cout << "
size from sum of parts " << sizeof(ph.filesize) + sizeof(ph.firstpd) + sizeof(ph.type);
cout << "
Class size from sizeof(class) " << sizeof(patchheader) << "
";
#endif
ofsnew.write(&ph,sizeof(ph));
return 0;
}

int main()
{
createpatchfile("c:\test.dat");
system("pause");
return 0;
}
[/code]

This results in the output:
Size of all parts 10
Class size from sizeof(Class) 12

i realise that the compiler is padding it out to a 4-byte boundary. but the hex from the file output is;
50 54 40 00 0C 00 00 00 0D 00 00 00
that decodes to
(byte 1 & 2) - 21584 ("PT")
then bytes 5,6 ,7,8 - 12 (sizeof(ph))
then bytes 9,10,11,12 - 13(sizeof(ph) + 1)

when i add another member to patchheader to make it 12 bytes long it becomes 16 bytes long
2 questions
1) how can i wither prevent it padding or cope with the padding to the 4 byte boundary so that my file is only 10 bytes long, without having to write a custom inserter / extractor

2) why when i made it 12 bytes long (meeting the 4 byte boundary) did it become 16 bytes.


Comments

  • SteveCSteveC Member Posts: 63
    Try
    http://www.dis.com/gnu/gcc/gcc_99.html
    And look at the 'packed' attribute

    : 1) how can i wither prevent it padding or cope with the padding to the 4 byte boundary so that my file is only 10 bytes long, without having to write a custom inserter / extractor
    Ultimately, you have to do this - even if packing works, there's no guarantee that it will always work (to your satisfaction), and it certainly isn't portable.
    You may find yourself on a machine with opposite endian-ess at some point, and then you're really going to have to do something.

    :
    : 2) why when i made it 12 bytes long (meeting the 4 byte boundary) did it become 16 bytes.
    No idea
  • whoiewhoie Member Posts: 672
    : Try
    : http://www.dis.com/gnu/gcc/gcc_99.html
    : And look at the 'packed' attribute
    :
    : : 1) how can i wither prevent it padding or cope with the padding to the 4 byte boundary so that my file is only 10 bytes long, without having to write a custom inserter / extractor
    : Ultimately, you have to do this - even if packing works, there's no guarantee that it will always work (to your satisfaction), and it certainly isn't portable.
    : You may find yourself on a machine with opposite endian-ess at some point, and then you're really going to have to do something.

    You could try a semi-portable binary format, try the C and C++ FAQ's for ideas. That won't help you with the padding, but at least you only have to write the inserter / extractor once.


    : : 2) why when i made it 12 bytes long (meeting the 4 byte boundary) did it become 16 bytes.
    : No idea

    Did you try placing the largest /type/ first in your class member list? Sometimes that can make a difference in the compiler's analysis. For example:
    [code=000000][color=ffffff]
    C:My Documents>cat foo.cpp
    #include

    class Patch_header {
    public:
    unsigned long n;
    unsigned long m;
    short int ph;
    short int pph;
    };

    int main()
    {
    Patch_header p;

    std::cout << "sizeof Patch_header = " << sizeof p << '
    ';

    return 0;
    }

    C:My Documents>foo
    sizeof Patch_header = 12

    C:My Documents>cat foo.cpp
    #include

    class Patch_header {
    public:
    short int ph;
    unsigned long n;
    unsigned long m;
    short int pph;
    };

    int main()
    {
    Patch_header p;

    std::cout << "sizeof Patch_header = " << sizeof p << '
    ';

    return 0;
    }

    C:My Documents>g++ -v
    Reading specs from /usr/lib/gcc-lib/i686-pc-cygwin/3.2/specs
    Configured with: /netrel/src/gcc-3.2-1/configure --enable-languages=c,c++,f77,java
    --enable-libgcj --enable-threads=posix --with-system-zlib --enable-nls
    --without-included-gettext --enable-interpreter --disable-sjlj-exceptions
    --disable-version-specific-runtime-libs --enable-shared
    --build=i686-pc-linux --host=i686-pc -cygwin --target=i686-pc-cygwin
    --enable-haifa --prefix=/usr --exec-prefix=/usr --sysconfdir=/etc
    --libdir=/usr/lib --includedir=/nonexistent/include --libexecdir=/usr/sbin
    Thread model: posix
    gcc version 3.2 20020818 (prerelease)

    C:My Documents>g++ -W -Wall -ansi -pedantic foo.cpp -o foo

    C:My Documents>foo
    sizeof Patch_header = 16
    [/color][/code]
    Note that the only differences are the order of the member list, yet I get 4 extra bytes with the sizes "unordered". It's not guaranteed to behave this way, it's just a thought...


    HTH,
    Will
    --
    http://www.tuxedo.org/~esr/faqs/smart-questions.html
    http://www.eskimo.com/~scs/C-faq/top.html
    http://www.parashift.com/c++-faq-lite/
    http://www.accu.org/


  • TheSpiderTheSpider Member Posts: 4
    You are correct
    [code]
    class patchheader //i dont like structures
    {
    public:
    short int type; // should read "PT" in ascii to show file is Patch file
    short int notused; //Padding
    unsigned long filesize; //filesize in bytes
    unsigned long firstpd; // location of first patchdata
    };

    [/code]

    gives sizeof(patchheader) as 12

    whereas
    [code]
    class patchheader //i dont like structures
    {
    public:
    short int type; // should read "PT" in ascii to show file is Patch file
    unsigned long filesize; //filesize in bytes
    unsigned long firstpd; // location of first patchdata
    short int notused; //Padding
    };
    [/code]
    gives sizeof(patchheader) 16.

    Why is that?
  • whoiewhoie Member Posts: 672
    : You are correct
    : [code]
    : class patchheader //i dont like structures
    : {
    : public:
    : short int type; // should read "PT" in ascii to show file is Patch file
    : short int notused; //Padding
    : unsigned long filesize; //filesize in bytes
    : unsigned long firstpd; // location of first patchdata
    : };
    :
    : [/code]
    :
    : gives sizeof(patchheader) as 12
    :
    : whereas
    : [code]
    : class patchheader //i dont like structures
    : {
    : public:
    : short int type; // should read "PT" in ascii to show file is Patch file
    : unsigned long filesize; //filesize in bytes
    : unsigned long firstpd; // location of first patchdata
    : short int notused; //Padding
    : };
    : [/code]
    : gives sizeof(patchheader) 16.
    :
    : Why is that?

    Because it has to be:

    9.2 Class members

    [...]

    12 Nonstatic data members of a (nonunion) class declared without an intervening accessspecifier are allocated so that [b]later members have higher addresses within a class object[/b]. The order of allocation of nonstatic data members separated by an access specifier is unspecified (11.1). [b]Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other[/b]; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).

    Note the first bolded portion that requires members to be stored at increasing addresses. In the second example (above), in order for the compiler to guarantee that all members will be aligned correctly (if your platform requires this), it has to pad the first member if short int does not have the same alignment requirements of unsigned long.

    Now, if it didn't pad the last member, then the size of our class will be sizeof(short int) + padding + sizeof(unsigned long) + sizeof(unsigned long) + sizeof(short int), which may or may not guarantee that all members will be correctly aligned in storage, so it may have to add padding at the end to guarantee this. Think about an array of these objects. If the size of an object was 14 bytes, and unsigned long required alignment on a 4 byte boundary, the second element in the array *will not be aligned correctly*. This is why you see the compiler "rounding up" on the size. Is that clear as mud? ;)


    HTH,
    Will
    --
    http://www.tuxedo.org/~esr/faqs/smart-questions.html
    http://www.eskimo.com/~scs/C-faq/top.html
    http://www.parashift.com/c++-faq-lite/
    http://www.accu.org/


  • DariusDarius Member Posts: 1,666
    : : You are correct
    : : [code]
    : : class patchheader //i dont like structures
    : : {
    : : public:
    : : short int type; // should read "PT" in ascii to show file is Patch file
    : : short int notused; //Padding
    : : unsigned long filesize; //filesize in bytes
    : : unsigned long firstpd; // location of first patchdata
    : : };
    : :
    : : [/code]
    : :
    : : gives sizeof(patchheader) as 12
    : :
    : : whereas
    : : [code]
    : : class patchheader //i dont like structures
    : : {
    : : public:
    : : short int type; // should read "PT" in ascii to show file is Patch file
    : : unsigned long filesize; //filesize in bytes
    : : unsigned long firstpd; // location of first patchdata
    : : short int notused; //Padding
    : : };
    : : [/code]
    : : gives sizeof(patchheader) 16.
    : :
    : : Why is that?
    :
    : Because it has to be:
    :
    : 9.2 Class members
    :
    : [...]
    :
    : 12 Nonstatic data members of a (nonunion) class declared without an intervening accessspecifier are allocated so that [b]later members have higher addresses within a class object[/b]. The order of allocation of nonstatic data members separated by an access specifier is unspecified (11.1). [b]Implementation alignment requirements might cause two adjacent members not to be allocated immediately after each other[/b]; so might requirements for space for managing virtual functions (10.3) and virtual base classes (10.1).
    :
    : Note the first bolded portion that requires members to be stored at increasing addresses. In the second example (above), in order for the compiler to guarantee that all members will be aligned correctly (if your platform requires this), it has to pad the first member if short int does not have the same alignment requirements of unsigned long.
    :
    : Now, if it didn't pad the last member, then the size of our class will be sizeof(short int) + padding + sizeof(unsigned long) + sizeof(unsigned long) + sizeof(short int), which may or may not guarantee that all members will be correctly aligned in storage, so it may have to add padding at the end to guarantee this. Think about an array of these objects. If the size of an object was 14 bytes, and unsigned long required alignment on a 4 byte boundary, the second element in the array *will not be aligned correctly*. This is why you see the compiler "rounding up" on the size. Is that clear as mud? ;)
    :
    :
    : HTH,
    : Will
    : --
    : http://www.tuxedo.org/~esr/faqs/smart-questions.html
    : http://www.eskimo.com/~scs/C-faq/top.html
    : http://www.parashift.com/c++-faq-lite/
    : http://www.accu.org/
    :
    :
    :

    On a side note as someone else alluded to, most compilers have a #pragma option or an option somewhere to set the alignment. I don't believe there is a standard way (I'd have to check, but I doubt it) to do this so any option you added would make your code non-standard. It would probably be best to use these facilities if it is necessary or worth it to be space efficient (a necessary example would be matching up to a OS or hardware data structure). If you intended to distribute this code a note to the effect that a compiler-specific packing/alignment option may be necessary should suffice. (You could also automate this, for example see the GNU automake/autoconf etc tools).

    "We can't do nothing and think someone else will make it right."
    -Kyoto Now, Bad Religion

  • Andre YoungAndre Young USAMember Posts: 0

    ___ { http://forcoder.org } free ebooks and video tutorials about { Visual Basic .NET, C#, Scratch, Python, Go, PL/SQL, Java, JavaScript, Visual Basic, Perl, R, Delphi, Assembly, Objective-C, C++, Ruby, MATLAB, Swift, PHP, C COBOL, Hack, FoxPro, ML, SAS, Dart, Bash, Scheme, Alice, Crystal, Clojure, D, LabVIEW, Scala, Apex, Awk, Rust, Erlang, Ada, F#, Fortran, Lua, ABAP, Kotlin, Prolog, Lisp, VBScript, Transact-SQL, Logo, Julia } ______________

Sign In or Register to comment.