~Linux C_13_变量存储布局

==== 数值变量 ====

#include<stdio.h>

const int A = 10; //.rodata
int a = 20; //.data
static int b = 30; //.data
int c; //.bss

int main(void)
{
  static int a = 40; //.data
  char b[] = "Hello world"; //
  register int c = 50; //eax寄存器

  printf("Hello world %d\n", c); 

  return 0;
}

程序加载运行时,.rodata段和.text段通常合并到一个Segment中,操作系统将这个Segment的页面只读保护起来,防止意外的改写。
.data和.bss在加载时合并到一个Segment中,这个Segment是可读可写的。

.bss段和.data段的不同之处在于,.bss段在文件中不占存储空间,在加载时这个段用0填充。全局变量,static变量(不管是函数里的还是函数外的)如果不初始化则初值也是0,也分配在.bss段。


 

==== 结构体 ====

#include <stdio.h>

int main(int argc, char** argv)
{
  struct {
    char a;
    short b;
    int c;
    char d;
  } s;

  s.a = 1;
  s.b = 2;
  s.c = 3;
  s.d = 4;
  printf("%u\n", sizeof(s));

  return 0;
}


结构体成员也是从低地址向高地址排列的,和数组类似。但有一点不同,结构体的各成员并不是一个紧挨一个排列的,中间有空隙,称为填充(Padding),这个结构体的末尾也有三个字节的填充,所以sizeof(s)的值是12。

填充方式:
--> a0bbccccd000 -->


合理设计结构体各成员的排列顺序可以节省存储空间:

struct {
    char a;
    char d;
    short b;
    int c;
} s;


gcc提供了一种扩展语法可以消除结构体中的填充字节:

struct {
  char a;
  short b;
  int c;
  char d;
} __attribute__((packed)) s; 

这样就不能保证结构体成员的对齐了,在访问b和c的时候可能会有效率问题,所以除非有特别的理由,一般不要使用这种语法。

 

 

==== 联合体 ====

#include <stdio.h>

typedef union {
    struct {
        unsigned int one:1;
        unsigned int two:3;
        unsigned int three:10;
        unsigned int four:5;
        unsigned int :2;
        unsigned int five:8;
        unsigned int six:8;
    } bitfield;
    unsigned char byte[8];
} demo_type;

int main(void)
{
    demo_type u = {{ 1, 5, 513, 17, 129, 0x81 }}; 
    //联合体如果用Initializer初始化,则只初始化它的第一个成员。初始化第二个byte[8]没有效果。

    printf("sizeof demo_type = %u\n", sizeof(demo_type));
    printf("values: u=%u,%u,%u,%u,%u,%u\n",
        u.bitfield.one, u.bitfield.two, u.bitfield.three,
        u.bitfield.four, u.bitfield.five, u.bitfield.six);
    printf("hex dump of u: %x %x %x %x %x %x %x %x \n",
        u.byte[0], u.byte[1], u.byte[2], u.byte[3],
        u.byte[4], u.byte[5], u.byte[6], u.byte[7]);

    return 0;
}

  一个联合体的各个成员占用相同的内存空间,联合体的长度等于其中最长成员的长度。比如u这个联合体占8个字节,如果访问成员u.bitfield,则把这8个字节看成一个由Bit-field组成的结构体,如果访问成员u.byte,则把这8个字节看成一个数组。
  联合体如果用Initializer初始化,则只初始化它的第一个成员,例如demo_type u = {{ 1, 5, 513, 17, 129, 0x81 }};初始化的是u.bitfield,但是通过u.bitfield的成员看不出这8个字节的内存布局,而通过u.byte数组就可以看出每个字节分别是多少了。

 


==== Bit-field ====

#include <stdio.h>

typedef struct {
  unsigned int one:1;
  unsigned int two:3;
  unsigned int three:10;
  unsigned int four:5;
  unsigned int :2; //表示空出两位
  unsigned int five:8; //之后会空出三位,但这是考虑到对齐的问题,一般只会出现在尾部。
  unsigned int six:8; //到了最后,可能会因为遵循“对齐”原则而有了编译器主观的做法,导致不连续。
} demo_type;

int main(void)
{
  demo_type s = { 1, 5, 513, 17, 129, 0x81 }; //在驱动中可以大量的运用这种方式来控制各个位的值。
  printf("sizeof demo_type = %u\n", sizeof(demo_type));
  printf("values: s=%u,%u,%u,%u,%u,%u\n",
    s.one, s.two, s.three, s.four, s.five, s.six);

  return 0;
}


 

http://hi.baidu.com/kebey2004/item/cdd58008ed9053c22f4c6bff

posted @ 2012-11-15 15:43  郝壹贰叁  阅读(246)  评论(0编辑  收藏  举报