473,397 Members | 1,960 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,397 software developers and data experts.

sizeof(MPEGLAYER3WAVEFORMAT)

MPEGLAYER3WAVEFORMAT is defined by:
Expand|Select|Wrap|Line Numbers
  1. typedef struct mpeglayer3waveformat_tag {
  2.   WAVEFORMATEX wfx;
  3.   WORD         wID;
  4.   DWORD        fdwFlags;
  5.   WORD         nBlockSize;
  6.   WORD         nFramesPerBlock;
  7.   WORD         nCodecDelay;
  8. } MPEGLAYER3WAVEFORMAT, *LPMPEGLAYER3WAVEFORMAT;
The size should be 30. However,
Expand|Select|Wrap|Line Numbers
  1.     cout<<"size of MP3 format: "<<sizeof(MPEGLAYER3WAVEFORMAT)<<endl;
  2. cout<<actual size: <<sizeof(WAVEFORMATEX)+ sizeof(WORD)+ \ 
  3. sizeof(DWORD)+ sizeof(WORD)+ sizeof(WORD)+ sizeof(WORD)<<endl;
produces:
size of MP3 format: 32
actual size: 30

Why 32 and 30? They are not equal?
May 13 '12 #1

✓ answered by weaknessforcats

I believe you are encountering pad bytes inserted by the compiler to align your struct members on int boundaries.

For example, thus struct:
Expand|Select|Wrap|Line Numbers
  1. struct MyStruct
  2. {
  3.    char data1;
  4.       int data3;
  5. };
has a sizeof 8 bytes. data1 is on an int boundary so to make data3 also on an int boundary three pad bytes are added between data1 and data3. So if you do this:
Expand|Select|Wrap|Line Numbers
  1. struct MyStruct
  2. {
  3.    char data1;
  4.    unsigned char pad1;
  5.    unsigned char pad2;
  6.    unsigned char pad3;
  7.       int data3;
  8. };
you will see that the sizeof the struct is still 8 bytes.

It's useful to know this because pad bytes are not written making it harder to locate your data in a file that you read back in.

5 2213
I tried the following test:
Expand|Select|Wrap|Line Numbers
  1.     struct mp3{//exact copy of MPEGLAYER3WAVEFORMAT 
  2.       WAVEFORMATEX wfx;
  3.       WORD         wID;
  4.       DWORD        fdwFlags;
  5.       WORD         nBlockSize;
  6.       WORD         nFramesPerBlock;
  7.       WORD         nCodecDelay;
  8.     }; 
  9.     cout<<"mp3: "<<sizeof(mp3)<<endl;
produces:
mp3: 32

But, if we removes the last WORD element nCodecDelay,
Expand|Select|Wrap|Line Numbers
  1.    struct mp3_short{//
  2.       WAVEFORMATEX wfx;
  3.       WORD         wID;
  4.       DWORD        fdwFlags;
  5.       WORD         nBlockSize;
  6.       WORD         nFramesPerBlock;
  7.     }; 
  8.  
  9.   cout<<"mp3 shortened: "<<sizeof(mp3_short)<<endl; 
produces:
mp3 shortened: 28

If the previous output 32 is correct, this should be 30, right? Since only a WORD of size 2 has been removed!
May 13 '12 #2
weaknessforcats
9,208 Expert Mod 8TB
I believe you are encountering pad bytes inserted by the compiler to align your struct members on int boundaries.

For example, thus struct:
Expand|Select|Wrap|Line Numbers
  1. struct MyStruct
  2. {
  3.    char data1;
  4.       int data3;
  5. };
has a sizeof 8 bytes. data1 is on an int boundary so to make data3 also on an int boundary three pad bytes are added between data1 and data3. So if you do this:
Expand|Select|Wrap|Line Numbers
  1. struct MyStruct
  2. {
  3.    char data1;
  4.    unsigned char pad1;
  5.    unsigned char pad2;
  6.    unsigned char pad3;
  7.       int data3;
  8. };
you will see that the sizeof the struct is still 8 bytes.

It's useful to know this because pad bytes are not written making it harder to locate your data in a file that you read back in.
May 14 '12 #3
Thanks for you reply.

You're right, and I used your example to write to a file:

Expand|Select|Wrap|Line Numbers
  1.     struct MyStruct
  2.     {
  3.       char data1;
  4.       int data3;
  5.     } ms;
  6.     ms.data1='a';
  7.     ms.data3=0xffffffff;
  8.     FILE*target=fopen("tmp",wb);
  9.     int i=0;
  10.     fwrite(&ms,sizeof(ms),1,target);
  11.     fclose(target);
and then I checked the file by
xxd tmp
It produces:
0000000: 6122 2a00 ffff ffff a"*.....
The bold part is the data we generated, the remaining part is garbage.

I guess that's fine if we use the programs compiled by the same compiler to retrieve information from this file.

But what if the programs are generated by compiler without padding? Anyway to avoid this?
May 14 '12 #4
Added
Expand|Select|Wrap|Line Numbers
  1. #pragma pack(1)
to fix the problem.

And I am not sure if this is the right choice ...
May 14 '12 #5
Banfa
9,065 Expert Mod 8TB
Adding #pragma pack(1) is not really the right choice because if it gets changed you suddenly can't read any of your old files. The packing of structures is done to allow the program to be efficient. Many processors can not access multi byte integers (like WORD and DWORD) from odd addresses or even for 4 byte integers from addresses that are not a multiple of 4.

That means for your packed structure is if you end up with a WORD or DWORD not starting at the correct alignment instead of just reading the value directly the compiler has to generate code to individually load each byte of the integer and reconstruct it in a register. Obviously (I think) this has a really big effect on program performance.

So the correct way to save a structure to a file is to decided what format the file is to have, what is going in each byte of the file, where each member of the structure will be stored and the write out the individual members of the structure rather than write the whole structure in 1 go. To make sure it is always done the same way and that it is read back correctly create functions to read and write the structure.
May 15 '12 #6

Sign in to post your reply or Sign up for a free account.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.