关于内存对齐
2012-04-13 13:00 javaspring 阅读(519) 评论(0) 编辑 收藏 举报
曾经接手一个网络视频监控程序,主要是上层软件通过发送控制指令获取网络视频板的视频数据和控制网络视频板,这应该是一个比较简单的流程!
一切的开发都很顺利,测试的时候,问题就来了,获取视频数据流的数据竟然是错误的,我糊涂了,把整个程序流程,用调试器一步一步地跑,到了发送视频指令的时候,返回指令操作错误的结果,怎么回事?我是按照视频的操作指令封装的数据包,内存显示数据包的内容是没有错误的,就是一个晚上,我不停地找"错误",只有偶然,我把sizeof()这个指令直接换掉,把数据包全部用一个BYTE的数据进行copy,程序成功执行!这时,我已经快晕了!
数据发送到网络板的数据包大小根本不是实际控制数据包的大小!
这时我才想起一个人, Stanley B. Lippman,他写的那一本书 "Inside object modale", 曾经提过这样的事情,编译器为了提高CPU的效率,会对struct 的结构进行优化,利用sizeof 可以得出不同的计算机上对 struct 的结构优化后的大小值.以前是看过,但是,却没有深刻理会,现在,吃了苦头,才明白!
这是我的理解,C++ 编译器为了使CPU的性能达到最佳,会对 struct 的内存结构进行优化,这是为了达到CPU数据传输总线的吞吐值,各个计算机的数据传输总线是不一样的,如32位的计算机的数据传输值是4 bytes,64位计算机数据传输是8 bytes,这样,struct 在默认的情况上,编译器会对 struct 的结构进行数据对齐((32位机)4的倍数或(64位机)8的倍数),如下面这段代码所示:
#include typedef struct tagPACKAGE { int intValue; char chValue1; char chValue2; } PACKAGE, * LP_PACKAGE; int main() { PACKAGE package; std::cout << "sizeof( package ) = " << sizeof( package ) << std::endl; return 0; }
程序执行结果为 8 ( sizeof( int ) + sizeof( char ) + sizeof( char ) + 对齐值 )为8. (我的机子是32位,4*2=8)一切都是编译器搞得自已头晕,但是为什么以前自已写的网络程序没有这种情况?同样的数据包传输,我并没有阻止编译进行强制对齐,我猜可能是操作系统都是一样(都是WinX系统)的才没有出现问题,而现在的网络视频板是内嵌式linux,对数据包的处理是纯数据(不经对齐的数据)是敏感的所以,才会出现这样的问题!这种情的解决方法是阻止编译器对数据包对齐,因为数据对齐的时候,编译器会塞入一些没有意义的数据对结构进行对齐,使用#pragma 强制编译器产生指定数据对齐方式,如下代码所示
#pragma pack(push) #pragma pack(1) typedef struct tagPACKAGE { int intValue; char chValue1; char chValue2; } PACKAGE, * LP_PACKAGE; #pragma pack(pop) typedef struct tagPACKAGE2 { int intValue; char chValue1; char chValue2; } PACKAGE2, * LP_PACKAGE2; int main() { PACKAGE package; PACKAGE2 package2; std::cout << "sizeof( package ) = " << sizeof( package ) << std::endl; std::cout << "sizeof( package2 ) = " << sizeof( package2 ) << std::endl; return 0; }
对指定的数据包编译时进行内存对齐,这样,也不会让编译器对其数据进行优化!
总结:
C++的编译器总是在背后做了很多事!网络数据处理或与内嵌式设备打交道的时候,这更应该小心!