惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

云风的 BLOG
云风的 BLOG
IT之家
IT之家
D
Docker
博客园 - 叶小钗
A
About on SuperTechFans
博客园_首页
Apple Machine Learning Research
Apple Machine Learning Research
Recorded Future
Recorded Future
Stack Overflow Blog
Stack Overflow Blog
腾讯CDC
V
V2EX
S
SegmentFault 最新的问题
量子位
P
Proofpoint News Feed
酷 壳 – CoolShell
酷 壳 – CoolShell
Latest news
Latest news
大猫的无限游戏
大猫的无限游戏
月光博客
月光博客
有赞技术团队
有赞技术团队
The GitHub Blog
The GitHub Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
I
InfoQ
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
D
DataBreaches.Net
G
GRAHAM CLULEY
P
Proofpoint News Feed
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Microsoft Security Blog
Microsoft Security Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Y
Y Combinator Blog
小众软件
小众软件
NISL@THU
NISL@THU
L
Lohrmann on Cybersecurity
aimingoo的专栏
aimingoo的专栏
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
I
Intezer
Last Week in AI
Last Week in AI
T
Threatpost
人人都是产品经理
人人都是产品经理
U
Unit 42
Security Latest
Security Latest
AWS News Blog
AWS News Blog
T
The Blog of Author Tim Ferriss
MongoDB | Blog
MongoDB | Blog
罗磊的独立博客
GbyAI
GbyAI
P
Palo Alto Networks Blog
G
Google Developers Blog
MyScale Blog
MyScale Blog
L
LangChain Blog

博客园 - 老羽

推荐AspNetPager分页控件 SqlServer2005中分页代码测试 WM中实现Splash动画效果 自定义合并多文件协议设计 JScript中Date.getTime转.Net中的DateTime POOM(Pocket Outlook Object Model)开发介绍及应用(转) 多线程执行多任务的DEMO GPRS管理与创建APN拨号连接 WM中电话相关的技巧 - 老羽 - 博客园 一道面试题题解 【转】Windows Mobile控制面板程序 [转]Windows Mobile上的服务程序 Smartphone2003开发总结一:Form总结 C++常用技巧一(整理收集) [转]CString,string,char*的综合比较 [转] C++ Windows字符和字符指针类型 [转]C++ int,char,string,CString类型转换(整理总结) C++字符串函数详解[转] Smartphone2003中实现焦点在ListView控件与其它控件中切换
.net中处理C/C++中的位域
老羽 · 2009-08-01 · via 博客园 - 老羽

2009-08-01 16:34  老羽  阅读(541)  评论()    收藏  举报

网上搜索了一些资料,发现多数都是把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/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。