百度了下,很多文章只是在告诉你一些内存对齐的理论,教你怎么算每个字段实际占用的内存。
例如这篇文章:
http://wenku.baidu.com/link?url=n1FoivBissfKXjxVpXr36oPEGUfoImMEM1FFhpMdeMhnhg48fs5o0RxB6S2VTbErn9MDoy299TeAazp-hffxACK29sx2tmFS1ulr-TaMela
这是纯粹的为面试而讲解。而且面试中问内存对齐也确实总有人问。
理论我们懂了,但是我相信没几人能深信自己总是可以准确算出来每个字段的准确大小。即便能算准,用途何在?
最重要的是:怎么让程序自动算出结构体中每个字段的准确的占用内存大小呢?
运行下面的代码吧,你就明白了。
你会发现,
直接用sizeof得到的内存大小是不准确的。
而准确的内存大小可以通过相减获得。
这在编程中是有实际意义的(很多时候,你会希望获取结构体中某个字段准确的长度)。
#define Enable
#ifdef Enable
struct st1
{
int i;
char c;
short s;
};
struct st2
{
char c;
int i;
short s;
};
void main()
{
st1 pst1;
st2 pst2;
unsigned int a1 = sizeof(pst1);
unsigned int a1_i = sizeof(pst1.i);
unsigned int a1_i_c = (unsigned int)(&pst1.c) - (unsigned int)(&pst1.i); // 下个字段的起始内存地址 - 当前字段的起始内存地址 = 当前字段实际占用的内存长度
unsigned int a1_c = sizeof(pst1.c);
unsigned int a1_c_c = (unsigned int)(&pst1.s) - (unsigned int)(&pst1.c); // 下个字段的起始内存地址 - 当前字段的起始内存地址 = 当前字段实际占用的内存长度
unsigned int a1_s = sizeof(pst1.s);
unsigned int a1_s_c = (unsigned int)(&pst1) + sizeof(pst1) - (unsigned int)(&pst1.s); // 结构体的截止内存地址 - 最后1个字段的起始内存地址 = 最后1个字段实际占用的内存长度
unsigned int a2 = sizeof(pst2);
unsigned int a2_c = sizeof(pst2.c);
unsigned int a2_c_c = (unsigned int)(&pst2.i) - (unsigned int)(&pst2.c); // 下个字段的起始内存地址 - 当前字段的起始内存地址 = 当前字段实际占用的内存长度
unsigned int a2_i = sizeof(pst2.i);
unsigned int a2_i_c = (unsigned int)(&pst2.s) - (unsigned int)(&pst2.i); // 下个字段的起始内存地址 - 当前字段的起始内存地址 = 当前字段实际占用的内存长度
unsigned int a2_s = sizeof(pst2.s);
unsigned int a2_s_c = (unsigned int)(&pst2) + sizeof(pst2) - (unsigned int)(&pst2.s); // 结构体的截止内存地址 - 最后1个字段的起始内存地址 = 最后1个字段实际占用的内存长度
}
#endif
另外,Intel、微软等公司曾经出过一道类似的面试题:
这个题目中也考察到了“相减”。
#include <iostream.h>
#pragma pack(8)
struct example1
{
short a;
long b;
};
struct example2
{
char c;
example1 struct1;
short e;
};
#pragma pack()
int main(int argc, char* argv[])
{
example2 struct2;
cout << sizeof(example1) << endl;
cout << sizeof(example2) << endl;
cout << (unsigned int)(&struct2.struct1) - (unsigned int)(&struct2) << endl;
return 0;
}
为何要考察呢?因为“相减”很有用,可以计算出准确的内存占用大小。
下面这段代码可以在linux的源码中看到,用了“相减”:
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_);
in_port_t sin_port; /* Port number. */
struct in_addr sin_addr; /* Internet address. */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};