.net中处理C/C++中的位域
2009-08-01 16:34 老羽 阅读(518) 评论(2) 编辑 收藏 举报网上搜索了一些资料,发现多数都是把C/C++中的位域当枚举([Flags]enum)处理,个人觉得能做枚举处理的应该是比较特殊的情况,有些情况肯定无法用枚举处理。比如以下情况,是某厂家获取GPS的一个结构体:
//GPS卫星的时间(UTC) typedef struct _GPS_UTC_Time { unsigned int iYear:12; // 年? unsigned int iMonth:4; // 月? unsigned int iDay:9; // 日? unsigned int iHour:5; // 小?时? unsigned int iMinute:7; // 分?钟? unsigned int iSeconds:7; // 秒? }GPS_UTC_Time, *PGPS_UTC_Time; //卫星信息
typedef struct _GPS_SATELLITE_INFO { unsigned int id :5; // 卫?星?编?号? unsigned int angleV:7; // 卫?星?仰?角? unsigned int angleH:9; // 卫?星?方?位?角? unsigned int sar :7; // 卫?星?心?噪?比? }GPS_SATELLITE_INFO, *PGPS_SATELLITE_INFO;
以上2个结构体,在.net中如果声明为枚举类型,肯定无法满足要求,因为结构体中的属性值都不是固定值;我按以下思路处理:
1.先在编译器中查看结构体的长度,因为C/C++存在内存对齐,所以需要查看真实的长度;
int size1=sizeof(GPS_UTC_Time); int size2=sizeof(GPS_DATA_INFO); printf("%d %d",size1,size2);//输出结果:4 8
2.声明.net结构体,并进行运算,计算结构体位域的值
因为是读取GPS,所以用ulong(8字节)存储GPS_UTC_Time的值,然后通过属性访问真实的结构体;
[StructLayout(LayoutKind.Sequential)] public struct GPS_DATA_INFO { const int GPS_MAX_SATELLITES_NUM = 12; //......其余字段略......
ulong gUTCTime; // 卫星时间 public DateTime UTCTime { get { if (gUTCTime > 0) { return new GPS_UTC_Time(gUTCTime).ToDateTime(); } return DateTime.Now; } }
}
public struct GPS_UTC_Time { public GPS_UTC_Time(ulong value) { // 5 7 7 9 4 12 iYear = (uint)((value << (64 - 12)) >> (64-12)); iMonth = (uint)((value << (64 - (12 + 4))) >> (64 - 4)); iDay = (uint)((value << (64 - (12 + 4+ 9))) >> (64 - 9)); iHour = (uint)((value << (64 - (12 + 4 + 9 + 7))) >> (64 - 7)); //位域是5位,实际是7位,可能是对 iHour字节对齐; iMinute = (uint)((value << (64 - (12 + 4 + 9 + 7 + 7))) >> (64 - 7)); iSeconds = (uint)((value << (64 - (12 + 4 + 9 + 7 + 7 + 7))) >> (64 - 7)); //奇怪的是,这里不需要对齐; } public DateTime ToDateTime() { if (iYear > 0 && iMonth > 0 && iDay > 0) { return new DateTime((int)iYear, (int)iMonth, (int)iDay, (int)iHour, (int)iMinute, (int)iSeconds).ToLocalTime(); } return DateTime.Now; } uint iYear; //12 年 uint iMonth; //4 月 uint iDay; //9 日 uint iHour; //5 小时 uint iMinute; //7 分钟 uint iSeconds; //7 秒 }
3.分析过程
计算位域时,通过位移运算,首先清除高位,然后清除不需要的低位,得到需要的位域;以一个测试过程为例:
GPS_UTC_Time time; time.iYear=2009; time.iMonth=11; time.iDay= 20; time.iHour=13; time.iMinute = 16; time.iSeconds=8; byte buffer[8]={0}; memcpy(buffer,(byte*)&time,8);
(1).得到buffer的值为:D9 B7 14 1A 10 04 00 00;因为是低位在前,高位在后,所以倒换次序后为:00 00 04 10 1a 14 b7 d9;
(2).转成为二进制后就可以很直观的看到数据存储的位置及值:
位域: 7 7 2 5 9 4 12
二进制: 0001000 0010000 00 01101 000010100 1011 011111011001
值: 8 16 13 20 11 2009
(3).位运算。
ulong value = 0x000004101a14b7d9; // 00 00 04 10 1a 14 b7 d9
iYear占12位,第一步左移 value << (64 - 12) ; 得到 0x7d90000000000000; 然后 >> (64-12),将高位移到低位:0x00000000000007d9;即2009,得到正确的值;
其余位域依次类推。。。。
作者:老羽(Michael-Zhangyu's Blog)
出处:http://michael-zhangyu.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。