c/c++中关于struct内存对齐问题

717次浏览

题:

struct st1{                                       struct st2{
          int i;                                                 char c;
          char c;                                             int i;
          short s;                                            short s;
       };                                                   };

上述两结构体在内存中占用字节是多少,即sizeof(struct st1)=?, sizeof(struct st2)=?
解:8, 12

思考:这是struct结构的内存对齐问题,结构体的内存布局依赖于CPU、操作系统、编译器及编译时的对齐选项。其主要有:

1)结构体内部成员对齐
对于结构体内部成员,通常会有这样的规定:各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。但是也可以看到,有时候某些字段如果严格按照大小紧密排列,根本无法达到这样的目的,因此有时候必须进行padding。各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调 整位置,空缺的字节编译器会自动填充也就是padding。如下图所示:

662029145240471388

图中st1,第一个为int型,占用4个字节,第二个为char型,其偏移量为4,char所占的字节数为1,则偏移量是其占用字节数的倍数,则仅列其后,第三个为short型,占用字节数为2,前面已有字节为5,不是2的倍数,所以char后面padding一个字节,使得short的其实地址为6,所以对齐后,共占用8个字节。同理可得str2占用12个字节

2)结构体之间对齐(此并不是考虑结构体内部的对齐,而是一组结构体的对齐,在计算单个结构体占用字节时并不考虑)

考虑整个结构体的对齐需求。ANSI C标准规定结构体类型的对齐要求不能比它所有字段中要求最严格的那个宽松,可以更严格。实际上要求结构体至少是其中的那个最大的元素大小的整数倍。因为有时候我们使用的是结构体数组,所以结构体的大小还得保证结构体数组中各个结构体满足对齐要求,同时独立的结构体与结构体数组中单个结构体的大小应当是一致的。


每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数32位机上是8)。程序员可以通过预编
译命令#pragma pack(n),n=1,2,4,8,16 来改变这一系数,其中的n 就是你要指定的“对齐系数”。

指定对齐:
一般的,可以通过下面的方法来改变缺省的对齐条件:
使用伪指令#pragma pack(n),编译器将按照n个字节对齐;
使用伪指令#pragma pack(),取消自定义的字节对齐方式;
注意:如果#pragma pack(n)中指定的n大于结构体中最大的成员的size,则其不起作用,结构体仍然按照size最大的成员进行对齐。

c/c++ struct按位分配成员

204次浏览

一个普通的c/c++中的struct如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct A
{
int d1;
int d2;
int d3;
int d4;
bool b1;
bool b2;
bool b3;
bool b4;
bool b5;
bool b6;
bool b7;
bool b8;
};

如果这里有一个大数组,如100万个A结构数组,肯定会想节省内存的。数据结构在固定的时候,还有什么办法吗?当然有了,就是按位分配成员。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct A
{
int d1;
int d2;
int d3;
int d4;
bool b1:1;
bool b2:1;
bool b3:1;
bool b4:1;
bool b5:1;
bool b6:1;
bool b7:1;
bool b8:1;
};

在成员名后面添加冒号和数字,就代表这个成员占用多少bit位。这样原来的一个bool是占一个字节8bit位的,现在就只占了1bit位了,而8个bool才占一个字节,是不是节省了N多内存了呢。
bool完全可以这么做的原因,是因为bool只有两个值true(1)、false(0),一个bit位完全可以表示并不失真。当然,任意类型在语法上都是可以这么指定位的。如d1、d2你明显知道取值是在0-1000以内,用short都太浪费,用char又不足。那么就可以分配11个bit位(高位符号位,也可以用unsigned d1:10),以次类推。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct A
{
int d1:11;
int d2:11;
int d3;
int d4;
bool b1:1;
bool b2:1;
bool b3:1;
bool b4:1;
bool b5:1;
bool b6:1;
bool b7:1;
bool b8:1;
};

这么做优点很明显了,节省内存,尤其是在大数组的情况下,可以节省很多。唯一不确定的是,大家都知道有一个struct内存对齐的东东。

c/c++结构相同但名字不同的的struct如何转换

258次浏览

比如一个struct1和struct2,里面的成员都是一样的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct struct1
{
int a;
int b;
float c;
};
 
struct struct2
{
int a;
int b;
float c;
};
 
struct1 T1;
struct2 T2;

现在如何把T2转换为struct1类型的?

试试

1
struct1 t1 = *(struct1*)&T2

不过这实际调用了struct1的copy构造函数,T2并未实际变为struct1类型,而是做为参数构造出一个全新的t1

c/c++多语言字符串格式保证参数顺序

1854次浏览

在c/c++字符串格式化还是很常用的,一般情况下也不会出现什么问题。但是,当开发多国语言的时候就会发现问题了。如:

1
format("%s对%s施放了法术-%s", a, b, c);

假设英文的一种翻译,仅做示例,语法错误勿怪。如下:

1
format("%s has been fired with %s by %s", a, b, c);

这就看出问题了,第一个的结果的是“a对b施放了法术c”,但第二个结果就是“a has been fired with b by c”,汉语就是“c对a施放了法术b,明显牛头不对马嘴。当然也有同学说了,可以在翻译的时候,来保证参数的使用顺序。如:

1
format("%s fired to %s with %s", a, b, c);

那好,英文ok了,那法语,德语,俄语,阿拉伯语呢,都能保持一致吗?显然是不可能的。

那么如何让参数自已找到正确的位置呢?很简单,c/c++里面可在格式化字符串里使用1$, 2$, 3$等表示位置。如下:

汉语:

1
format("%1$s对%2$s施放了法术-%3$s", a, b, c);

英文:

1
format("%2$s has been fired with %3$s by %1$s", a, b, c);

这样的结果就是“b has been fired with c by a”。