如何使下面的C结构更有内存效率



我正试图解决一项极具挑战性的编程任务。我们得到了以下64位结构,它允许我们存储精确到分钟的时间点:

typedef struct
{
unsigned char day;  //1 Byte
unsigned char month; //1 Byte
unsigned int year;  //4 Bytes
unsigned char hours; //1 Byte
unsigned char minutes; //1 Byte
} Time; //4 Bytes are probably used for padding

这个结构的大小是12字节(我检查过了,这个结构确实占用了太多空间(。任务是将大小减少到8字节,我们不允许使用联合。我们应该使用很多这样的结构,因此我们想要减小内存大小。

我唯一能想到的就是把unsigned int改成unsigned short,但我们怎么能去掉另外两个字节呢?

问候

这里的主要问题是char没有对齐要求,但int有4字节对齐的要求(在32位系统上(。这意味着它必须从一个可以被4整除的地址开始。结构保证从一个对齐的地址开始,所以你得到的可能是:

unsigned char day;  //1 Byte
unsigned char month; //1 Byte
// 2 byte padding!
unsigned int year;  //4 Bytes
unsigned char hours; //1 Byte
unsigned char minutes; //1 Byte
// 2 byte padding!

前两个填充字节用于确保int对齐,后两个用于确保结构数组中的下一个结构从对齐的地址开始。

修复很简单,只需将year移动到结构的顶部:

unsigned int year;  //4 Bytes
unsigned char day;  //1 Byte
unsigned char month; //1 Byte
unsigned char hours; //1 Byte
unsigned char minutes; //1 Byte

现在这个结构应该是8字节大,并且没有填充。

您当前的结构,因为sizeof(Time) == 12sizeof(unsigned int) == 4的布局如下:

typedef struct
{
unsigned char day;  //1 Byte
unsigned char month; //1 Byte
// 2 bytes padding to align the `unsigned int`
unsigned int year;  //4 Bytes
unsigned char hours; //1 Byte
unsigned char minutes; //1 Byte
// 2 bytes padding
} Time; 

您可以通过先移动year将大小减小到8。此处无需填充:

typedef struct
{
unsigned int year;  //4 Bytes
unsigned char day;  //1 Byte
unsigned char month; //1 Byte
unsigned char hours; //1 Byte
unsigned char minutes; //1 Byte
} Time; 

编译器根据结构的下一个字段的对齐方式来对齐数据,在您的情况下,有两个对齐方式为1的char字段(任何地址都可以有效地保存字符(,但int类型(32位(的对齐要求为4字节,因此,由于第二个char元素为2时的偏移量,它需要添加两个对齐空间以使其正确对齐(到4的地址倍数(,它还使整个struct对齐,因此当结构端到达时,该类型的下一个结构的对齐为4(以适当地保留数组中整个结构的对齐(,因此,它需要在结构端再添加两个字节。这就形成了您在代码中观察到的四个字节。

要进行优化,只需将大字段放在结构上的第一位,然后在最后用较小的数据填充(对齐要求较少(通过这种方式,结构与较大的场更好地对齐,并且场倾向于填充通过对齐形成的孔。如果您使用过,请改为:

struct my_struct {
double        time_as_double;  // normally 8 byte alignment
char         *timezone;        // 8 byte alignment in 64bit architectures.
int           year;            // 4 byte alignment
unsigned char month,           // one byte alignment
mday,            // one byte alignment
hour,            // one byte alignment
min,             // one byte alignment
sec;             // one byte alignment
// seven more bytes of alignment to comply with 8 byte alignment for the
// full structure (to allow it to form arrays)
};

你会得到一个32字节的结构(最坏的情况是,它产生了25个压缩字节,所以8的下一个倍数是32(

#include <stdio.h>
struct my_struct {
double        time_as_double;  // normally 8 byte alignment
char         *timezone;        // 8 byte alignment in 64bit architectures.
int           year;            // 4 byte alignment
unsigned char month,           // one byte alignment
mday,            // one byte alignment
hour,            // one byte alignment
min,             // one byte alignment
sec;             // one byte alignment
// seven more bytes of alignment to comply with 8 byte alignment for the
// full structure (to allow it to form arrays)
};
int main()
{
printf("sizeof (struct my_struct) == %zun", sizeof (struct my_struct));
}

其产生:

$ a.out
sizeof (struct my_struct) == 32
$ _

最新更新