2

So in my code I have the following structs defined in a header file:

test.h:

#ifndef TEST
#define TEST 
typedef struct struct1 {
    uint8_t a;
    uint16_t b;
    uint16_t c;
} struct1;

typedef struct struct2 {
    uint8_t a;
    uint8_t b;
    uint8_t c;
    uint8_t d;
    uint8_t e;
    struct struct1 f;
} struct2;
void doStuff(struct struct2 * s);
#endif

When I declare a struct2 and call a function with a pointer to it, values assigned inside the function don't match the values read outside of that function

main.c:

#include <stdint.h>
#include <stdio.h>
#include "test2.h"
#include "test.h"
int main(){
    struct struct2 s;
    s.a=0;s.b=0;s.c=0;s.e=0;
    printf("Main's s's size: %d\n", sizeof(s));
    doStuff(&s);
}

test.c:

#include <stdint.h>
#include <stdio.h>
#include "test.h"
void doStuff(struct struct2 * s){
    printf("doStuff's size: %d\n", sizeof(*s));
}

test2.h:

#pragma pack(1)

When printing their sizes, sizeof(*s) inside doStuff returns 12, whileas inside the main function sizeof(s) returns 10. When comparing the addresses of each of the internal values, s.a through s.e match inside and outside the function, s.f and s.f.a are one off, and s.f.b and s.f.c are two off.

Any idea what's going on here?

(note: Question has been closed as a duplicate of what I don't believe it is a duplicate of. The real problem stems from test2.h's use of '#pragma pack(1)'. Moving the #include of test2.h to after that of test.h makes it work as expected. To run above, 'gcc -o test test.c main.c', under GCC 4.4)

Ross Aiken
  • 912
  • 1
  • 6
  • 16
  • 4
    Is the call to doStuff and the function definition in different files? If so you may have included something that changes packing. – John May 16 '13 at 01:32
  • 2
    To add to John's comment, there could be a `#pragma pack` or similar statement somewhere in your code, or it could be that you have two translation units with different compiler command line arguments for packing (possibly coordinated by an IDE). Look for both things mentioning packing, and any mention of "optimise for space" (i.e. pack tightly) vs "optimise for speed" (i.e. arrange optimal alignment for speed). – Tony Delroy May 16 '13 at 01:52
  • Yes, doStuff is called in one c file, its prototype is given in a separate header file, and its declaration is in a different c file – Ross Aiken May 16 '13 at 01:52
  • Looking at the code, one of the headers included by the main c file does contain '#pragma pack(1)'. Once I get a chance, I'll test this on the machine where this was happening and post back here with an answer. – Ross Aiken May 16 '13 at 01:58
  • Worked the same for me with/without the #pragma pack(1). Disclaimer: I used an older VC++ compiler and used unsigned char and unsigned int. – Peter L. May 16 '13 at 03:47
  • Can you post the complete header and .c files (including printing the sizes) along with the command line and version of the compiler used to build the program? – Michael Burr May 16 '13 at 04:49
  • Also, I fail to see how a question asking how one struct is sized differently when passed between files is a duplicate of one asking why the size of some structs is bigger than the sum of their parts. Yes, as I can see now the result was likely due to memory alignment (and using pragma commands may fix this), but imo these are still very different questions (with somewhat similar answers) – Ross Aiken May 16 '13 at 14:52

3 Answers3

1

There is a concept called "Structure Padding". In simple Words it says that uint16_t can take only memory addresses which are multiple of 2. Char and uint8_t can take any memory as they go with multiple of 1. So to adjust in this way Sometimes there are empty pads left So when we use sizeof() it also counts these empty pads.

jinal shah
  • 122
  • 4
0

I'm glad to answer your question. The main idea is about the "Memory Alignment". You can search something about "Memory Alignment" by Google.

Every complier has the different result. In Visual Studio 2012, I get the different result with yours.

Here I get another website about this question. Maybe it can help you. Why the size of these two structs are different?

Community
  • 1
  • 1
vipygd
  • 78
  • 7
0

I can't reproduce your results (your working code would have been helpful). Here is mine, which prints ((gcc-4.6.3 release with patches [build 20121012 by perlmingw.sf.net]) 4.6.3)

$ ./structs
main: 12 12
0 0 0 0 0 0 0 0
0 1 2 3 4 6 8 10
doStuff: 12 12
0 0 0 0 0 5 6 7

and that looks perfectly good to me. The size of s is 12 bytes, so is the size of struct2. After initialising all fields to zero, they are zero. Offsets from the beginning of the struct are OK (based on the requested types), knowing that C structure alignment is based on the biggest size native type in the structure. Ie you have a uint16_t in struct1 so the struct has to be aligned to 16 bit word boundary, which explains why f starts at offset 6 instead of 5.

Once doStuff returns I get the correct values what doStuff did.

#include <stdio.h>
#include <stdint.h>
#include <stddef.h>

typedef struct struct1 {
  uint8_t a;
  uint16_t b, c;
} struct1;

typedef struct struct2 {
  uint8_t a, b, c, d, e;
  struct struct1 f;
} struct2;

void doStuff(struct struct2 * s)
{
  printf("doStuff: %lu %lu\n", sizeof(*s), sizeof(struct struct2));  
  s->f.a = 5; s->f.b = 6; s->f.c = 7;
}

int main(int argc, char** argv)
{
  struct struct2 s;

  printf("main: %lu %lu\n", sizeof(s), sizeof(struct struct2));
  s.a=s.b=s.c=s.d=s.e=s.f.a=s.f.b=s.f.c=0;
  printf("%u %u %u %u %u %u %u %u\n", s.a,s.b,s.c,s.d,s.e,s.f.a,s.f.b,s.f.c);
  printf("%u %u %u %u %u %u %u %u\n",
     offsetof(struct struct2, a), offsetof(struct struct2, b),
     offsetof(struct struct2, c), offsetof(struct struct2, d),
     offsetof(struct struct2, e), offsetof(struct struct2, f.a),
     offsetof(struct struct2, f.b), offsetof(struct struct2, f.c));
  doStuff(&s);
  printf("%u %u %u %u %u %u %u %u\n", s.a,s.b,s.c,s.d,s.e,s.f.a,s.f.b,s.f.c);
  return 0;
}
user1666959
  • 1,805
  • 12
  • 11