tags:

views:

621

answers:

9

I have the following two structs:

The problem is the sizeof(Content) returns 160. The struct consists of 11 shorts, 6 ints, 76 chars, 7 floats, 1 double, totally adding to 158 bytes. I have counted three times and there is still a 2 byte difference.

typedef struct TIME_T { 
    short year,mon,day; 
    short hour,min,sec; 
} TIME;

typedef struct { 
    int no; 
    char name[20]; 
    char Code[10]; 
    char DASType[10]; 
    short wlen; 
    float VLtd; 
    int samp; 
    int comp; 
    int locationID; 
    short TranMode; 
    char TranIns[12]; 
    short TimerMode; 
    char ClkType[12]; 
    float ClkErr; 
    float lat; 
    float lon; 
    float alt; 
    float azimuth,incident; 
    short weight; 
    short veloc; 
    int oritype; 
    char seismometer[12]; 
    double sens; 
    TIME start_time; 
    int record_samples; 
} Content;

I write a small piece of code to print the position of each variables in the struct, and suddenly I find the float wlen takes 4 bytes. My code is as follows:

int main(void)
{   
    Content content;
    printf("Sizeof Content: %d\n", sizeof(content));
    printf("Sizeof int content.no: %d\n", (int)&content.name - (int)&content.no);
    printf("Sizeof char[20] content.name: %d\n", (int)&content.Code - (int)&content.name);
    printf("Sizeof char[10] content.Code: %d\n", (int)&content.DASType - (int)&content.Code);
    printf("Sizeof char[10] content.DASType: %d\n", (int)&content.wlen - (int)&content.DASType);
    printf("Sizeof short content.wlen:  %d\n", (int)&content.VLtd - (int)&content.wlen);
    printf("Sizeof float content.VLtdL %d\n", (int)&content.samp - (int)&content.VLtd);
    printf("Sizeof int content.samp: %d\n", (int)&content.comp - (int)&content.samp);
    printf("Sizeof int content.comp: %d\n", (int)&content.locationID - (int)&content.comp);
    printf("Sizeof int content.locationID: %d\n", (int)&content.TranMode - (int)&content.locationID);
    printf("Sizeof short content.TranMode: %d\n", (int)&content.TranIns - (int)&content.TranMode);
    printf("Sizeof char[12] content.TranIns: %d\n", (int)&content.TimerMode - (int)&content.TranIns);
    printf("Sizeof short content.TimerMode: %d\n", (int)&content.ClkType - (int)&content.TimerMode);
    printf("Sizeof char[12] content.ClkType: %d\n", (int)&content.ClkErr - (int)&content.ClkType);
    printf("Sizeof float content.ClkErr: %d\n", (int)&content.lat - (int)&content.ClkErr);
    printf("Sizeof float content.lat: %d\n", (int)&content.lon - (int)&content.lat);
    printf("Sizeof floatcontent.lon: %d\n", (int)&content.alt - (int)&content.lon);
    printf("Sizeof floatcontent.alt: %d\n", (int)&content.azimuth - (int)&content.alt);
    printf("Sizeof floatcontent.azimuth: %d\n", (int)&content.incident - (int)&content.azimuth);
    printf("Sizeof floatcontent.incident: %d\n", (int)&content.weight - (int)&content.incident);
    printf("Sizeof short content.weight: %d\n", (int)&content.veloc - (int)&content.weight);
    printf("Sizeof short content.veloc: %d\n", (int)&content.oritype - (int)&content.veloc);
    printf("Sizeof int content.oritype: %d\n", (int)&content.seismometer - (int)&content.oritype);
    printf("Sizeof char[12] content.seismometer: %d\n", (int)&content.sens - (int)&content.seismometer);
    printf("Sizeof double content.sens: %d\n", (int)&content.start_time - (int)&content.sens);
    printf("Sizeof TIME content.start_time: %d\n", (int)&content.record_samples - (int)&content.start_time);
    printf("Sizeof int content.record_samples: %d\n", sizeof(content.record_samples));

    getchar();
    return 0;
}

The output is as follows:

Sizeof int content.no: 4
Sizeof char[20] content.name: 20
Sizeof char[10] content.Code: 10
Sizeof char[10] content.DASType: 10
Sizeof short content.wlen:  4
**Sizeof float content.VLtdL 4**
Sizeof int content.samp: 4
Sizeof int content.comp: 4
Sizeof int content.locationID: 4
Sizeof short content.TranMode: 2
Sizeof char[12] content.TranIns: 12
Sizeof short content.TimerMode: 2
Sizeof char[12] content.ClkType: 12
Sizeof float content.ClkErr: 4
Sizeof float content.lat: 4
Sizeof floatcontent.lon: 4
Sizeof floatcontent.alt: 4
Sizeof floatcontent.azimuth: 4
Sizeof floatcontent.incident: 4
Sizeof short content.weight: 2
Sizeof short content.veloc: 2
Sizeof int content.oritype: 4
Sizeof char[12] content.seismometer: 12
Sizeof double content.sens: 8
Sizeof TIME content.start_time: 12
Sizeof int content.record_samples: 4

The compiler is MSVC8, no UNICODE defined, no other macro defined. It's x86.

I tried to compile the same code in gcc version 3.4.4, the output is the same. Sizeof short content.wlen: 4

Can anyone explain this to me?

Thanks in advance.

EDIT: Thanks for answering! I have got it now.

+19  A: 

short answer only: alignment

dfa
no pun intended?
abyx
+8  A: 

You cannot work out the size of a struct simply by adding the sizes of all its components - the compiler is allowed to insert padding between the fields, and frequently does.

anon
+2  A: 

You're not calculating size of the fields, but the "distance" between them, so I guess what you're seeing is word alignment within the struct.

Brian Rasmussen
+4  A: 

Alignment - on a 32 bit architrecture its a lot more efficient to pass memory around in 32 bit chunks. You wouldnt actually save any memory at all by storing a short in 16 bits, as it would still be part of an associated 32 bit word.

Visage
But usually two adjacent shorts in a struct will be packed together as the usual rule is for padding to be used to put each member at its "natural" alignment. Of course, the whole issue is implementation defined behavior, so your mileage will vary considerably.
RBerteig
+3  A: 

Does adding another short to the structure expand the size, or keep it the same? My bet is it stays the same size.

Both compilers are working to keep your structure 8-byte aligned (I presume), so some field is going to be "expanded" to take up the extra room; actual operations on that field will behave as if it were the "proper" size.

Kevin Montrose
It will likely stay the same size if and only if the new short is inserted adjacent to the wlen member so that the existing padding bytes can be re-used. Inserting it in nearly any other location is likely to cause two more padding bytes to happen.
RBerteig
+3  A: 

Structure members are often aligned on 4-byte boundaries if the compiler finds that access will be more convenient that way. Similar behaviour occurs with char.

You can try to optimize memory footprint of your structure by putting shorts together, so that two consecutive shorts use a single 32-bit word. Don't forget to double check compiler results.

mouviciel
+2  A: 

According to the C standard, every native type in memory has to be aligned to its size, but isn't directly related to your problem. What you should be looking into is struct packing.

Tal Pressman
+1  A: 

Take a look at pahole, short for Poke-a-Hole. It's one of the DWARF2 tools used to find holes in structs, holes being spaces between members due to alignment rules, that could be used for new struct entries or be reorganized to reduce the size.

Read more about it in this LWN article by the author of the program, Arnaldo Carvalho de Melo.

There's not many tutorials to be found on the net, but this wiki-page at CERN is somewhat helpful.

Claes Mogren
+2  A: 

As dfa said, it's due to alignment. One "good practice" that can help reduce the size of your structures is to order it's member by their individual size (actually their individual alignment, but the size is often good enough) starting with the largest member.

This is not always true, but most of the time.

JJacobsson