编程随想录
CSDN拆迁户 @2014-04-07

导航

 


Index
   (1) sizeof(long long / int / short)
   (2) 结构体字节对齐;
   (3) 柔性数组(flexible array);


(1) sizeof(long long / int / short)
long 和 int 范围是[-2^31,2^31),即-2147483648~2147483647。
而unsigned范围是[0,2^32),即0~4294967295。也就是说,常规的32位整数只能够处理40亿以下的数。
相比于C++98标准,C++11整型的最大改变就是多了long long。
long long整型有两种:long long和unsigned long long。在C++11中,标准要求long long整型可以在不同平台上有不同的长度,但至少有64位。我们在写常数字面量时,可以使用LL后缀(或是ll)标识一个long long类型的字面量,而ULL(或ull、Ull、uLL)表示一个unsigned long long类型的字面量。比如:

long long int lli = -9000000000000000000LL;
unsigned long long int ulli = -9000000000000000000ULL;

A: Win7 x64 + MinGW
sizeof(short)) = 2
sizeof(int)) = 4
sizeof(long)) = 4
sizeof(long long)) = 8

比如对于有符号的,下面的类型是等价的:long long、signed long long、long long int、signed long long int;而unsigned long long和unsigned long long int也是等价的。

同其他的整型一样,要了解平台上long long大小的方法就是查看<climits>(或<limits.h>中的宏)。与long long整型相关的一共有3个:LLONG_MIN、LLONG_MAX和ULLONG_MIN,它们分别代表了平台上最小的long long值、最大的long long值,以及最大的unsigned long long值。

#include <climits>

int main() {
    long long ll_min = LLONG_MIN;
    long long ll_max = LLONG_MAX;
    unsigned long long ull_max = ULLONG_MAX;

    printf("min of long long: %lld\n", ll_min); // min of long long: -9223372036854775808
    printf("max of long long: %lld\n", ll_max); // max of long long: 9223372036854775807
    printf("max of unsigned long long: %llu\n", ull_max);   // max of unsigned long long: 18446744073709551615
}
// 编译选项:g++ -std=c++11 2-2-1.cpp
在代码清单2-5中,将以上3个宏打印了出来,对于printf函数来说,输出有符号的long long类型变量可以用符号%lld,而无符号的unsigned long long则可以采用%llu。18446744073709551615用16进制表示是0xFFFFFFFFFFFFFFFF(16个F),可知在我们的实验机上,long long是一个64位的类型。



(2) 结构体字节对齐;

1.一般结构体的sizeof,
   gcc和cl编译器有所不同,以cl为例,
   cl编译器下,
    (1)结构体成员变量的首地址能够被这个成员(该成员可能是个结构体)最宽基本类型成员的大小所整除;
    (2)sizeof(struct)的值等于struct内最大基本元素长度的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。
    (3)每个成员相对结构体首地址的偏移量是该成员长度的整数倍,
   gcc以4的整数倍对齐;
 
2.包含结构体成员的结构体,
    (1)在寻找最宽基本类型成员时,应当包括“子结构体”的成员;
    (2)“子结构体变量”的首地址能够被其最宽基本类型成员的大小所整除;
    struct S1 {
       char c;
       int i;
     }; //sizeof(S1) = 8
    struct S3 {
      char c1;
      S1 s;  //8 bytes
      char c2
    };
    S1或S3的最宽简单成员的类型都为int,所以S3的最宽简单类型为int;
    S3::s的类型是struct S1,其起始地址是sizeof(int)的整数倍(struct S1最宽的成员是int型);
    S3占用内存如下
     S3:c1占1字, 填充3字, S1:c占一字, 填充3字, S1:i占4字, S3:c2占1字, 填充3字,
故sizeof(struct S3) = 16;

  
3.改变缺省的对齐条件, 即“成员相对于结构体首地址的偏移量,是成员大小的整数倍”,变成了“成员相对于结构体首地址的偏移量,是对齐字节的整数倍”
    VC6中使用语法如下:
    #pragma pack(push) // 将当前pack设置压栈保存
   #pragma pack(2) //按照2字节对齐
   struct S1
  {
    char c;
    int i;
    }; // 6 bytes
   struct S2{
     char  c1;
     struct S1 sss;
     char c2
   };
   #pragma pack(pop)
   或者不保存压栈,#pragma pack(8)和#pragma pack()成对出现;

   #pragma pack(n),如果n比结构体成员的sizeof值小,那么该成员的偏移量应该以此值为准,结构体成员的偏移量应该取二者的最小值。
   上面对定义中最宽的int,和#pragma pack(2)比较,所以对齐条件是2字节;
   char S1::c占1字,int S1::i宽度是4,这里不以4而是以2对齐,所以int S1::i的起始位置是2,sizeof(S1) == 6。
 
   注* 没有任何成员的“空结构体”占1byte;


二:含位域结构体的sizeof

使用位域的主要目的是压缩存储,其大致规则为:
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。



测试:
struct test
{
  char a:1; //占1bit
  char b:2;  //占 1bit
  long c:3; //占4 byte
  char d:2;  //占1bit
};
test t1;
int len=sizeof(t1); 
根据前面讲的计算方法,a和b 占2bit,占用第1个字节,但该结构体里占内存最大的是long c ,占用4 byte,所以a和b一起占4 byte; c 占4 byte; d 占4 byte。所以最后总共占12 byte


struct test
{
  char a:1;
  char :2;
  char b:3;
  long c:2;
};
test t1;
int len=sizeof(t1);   //len=8


struct test
{
  char a:1;
  char :2;
  char b:3;
  char c:2;
};
test t1;
int len=sizeof(t1);   //len=1





(3) 柔性数组(flexible array)
C99中,结构中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员,但结
构中的柔性数组成员前面必须至少一个其他成员。 柔性数组成员允许结构中包含一个大小可
变的数组。sizeof返回的这种结构大小不包括柔性数组的内存。包含柔性数组成员的结构用
malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组
的预期大小。
柔性数组到底如何使用呢?看下面例子:
typedef struct st_type
{
     int i;
     int a[0];
}type_a;
有些编译器会报错无法编译可以改成:
typedef struct st_type
{
     int i;
     int a[];
}type_a;

这样我们就可以定义一个可变长的结构体,用 sizeof(type_a)得到的只有 4,就是
sizeof(i)=sizeof(int)。那个 0 个元素的数组没有占用空间,而后我们可以进行变长操作了。通
过如下表达式给结构体分配内存:

type_a *p = (type_a*)malloc(sizeof(type_a) + 100*sizeof(int));

这样我们为结构体指针 p 分配了一块内存(该内存块大小远大于结构的大小)。用 p->item[n]就能简单地访问可变长元素。
但是这时候我们再用 sizeof(*p)测试结构体的大小,发现仍然为 4。
回忆一下我们前面讲过的“模子” 。在定义这个结构体的时候,模子的大小就
已经确定不包含柔性数组的内存大小。只是说
在使用柔性数组时需要把它当作结构体的一个成员,仅此而已。再说白点,柔性数组其实与
结构体没什么关系,算不得结构体的正式成员。

需要说明的是:C89不支持这种东西,C99把它作为一种特例加入了标准。但是,C99
所支持的是 incomplete type,而不是 zero array,形同 int item[0];这种形式是非法的,C99支
持的形式是形同 int item[];只不过有些编译器把 int item[0];作为非标准扩展来支持,而且在
C99发布之前已经有了这种非标准扩展了,C99发布之后,有些编译器把两者合而为一了。
当然,上面既然用 malloc函数分配了内存,肯定就需要用 free函数来释放内存:
free(p);

参考:
结构体对齐 http://blog.csdn.net/yinkaizhong/archive/2009/12/06/4951288.aspx
柔性数组 http://blog.csdn.net/yiruirui0507/archive/2010/07/22/5756328.aspx

posted on 2011-05-26 17:14  dos5gw  阅读(261)  评论(0编辑  收藏  举报