为什么这个结构根据它的使用位置而表现不同?

时间:2013-05-16 01:27:39

标签: c struct

因此,在我的代码中,我在头文件中定义了以下结构:

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

当我声明struct2并使用指向它的指针调用函数时,在函数内分配的值与在该函数外部读取的值不匹配

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)

当打印它们的尺寸时,doStuff内的sizeof(* s)返回12,而main函数sizeof(s)内部返回10.当比较每个内部值的地址时,sa到se匹配函数内部和外部,sf和sfa是一个关闭,sfb和sfc是两个关闭。

知道这里发生了什么吗?

(注意:问题已被关闭,因为我不相信它是重复的。真正的问题源于test2.h使用'#pragma pack(1)'。移动#include of在test.h之后的test2.h使它按预期工作。要运行上面的'gcc -o test test.c main.c',在GCC 4.4下)

3 个答案:

答案 0 :(得分:1)

有一个名为“结构填充”的概念。简单来说,它表示uint16_t只能占用2的倍数的内存地址.Char和uint8_t可以占用任何内存,因为它们具有1的倍数。所以以这种方式调整有时候还有空的垫子所以当我们使用sizeof时()它也计算这些空垫。

答案 1 :(得分:0)

我很高兴回答你的问题。 主要思想是关于“记忆对齐”。您可以通过Google搜索“内存对齐”的内容。

每个编制者都有不同的结果。在Visual Studio 2012中,我得到了与您不同的结果。

我在这里得到另一个关于这个问题的网站。也许它可以帮到你。 Why the size of these two structs are different?

答案 2 :(得分:0)

我无法重现您的结果(您的工作代码会有所帮助)。这是我的,打印((gcc-4.6.3发布补丁[build by 2012 of 2012 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

这看起来对我很好。 s的大小是12个字节,struct2的大小也是如此。将所有字段初始化为零后,它们为零。从结构开头的偏移是可以的(基于所请求的类型),知道C结构对齐基于结构中最大的本机类型。即你在struct1中有一个uint16_t所以结构必须与16位字边界对齐,这解释了为什么f从偏移量6而不是5开始。

doStuff返回后,我会得到doStuff所做的正确值。

#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;
}