AD补码数据和位段结构体
2012-05-08 13:52
831 查看
转载自:
http://blog.sina.com.cn/s/blog_4513dde60100o6qn.html
这是调电路时遇到的问题。由12位AD传来的数据放入字长为32b的存储器里。其中存储器的数据线中低12b与AD相连,其余接地。AD数据使用12位补码表示。于是字长为32b的存储器里每个字存放的数据是由低12b的AD数据和高20b的0组成。如果再利用运行于CPU上的C程序对这些存储器中的数据进行处理,则无法直接使用。
例如,AD传送了数据-2,用12b的补码表示就是0xffe,但是在C程序中如果直接用32b的int类型来操作,就成了0xffe == 4094,两者相去甚远。只有进行一些附加的操作,比如,判断数据的11b(最低位为0b)是否等于1,若是,则将数据的高20b置1,写成代码就是:
if ((x & 0x800) != 0) x |= 0xfffff000;
我想,在C的层面上是否有更简便而灵活的操作方法。假如说我们的AD换成了4b,6b,8b,14b,16b,18b,20b等等(好像AD没有这么多类),那么上面代码中的0x800和0xfffff000就要换成相应的数值才行,虽然不很麻烦,但也有点麻烦。
那天看以前写的程序,发现位段结构体中位域都使用unsigned修饰的。我想,位域大概也可以用signed修饰吧!好像从来没有这样做过。如果能行,我们是不是找到了一种应对AD有符号补码数据的灵活方法呢?于是写了一段代码验证想法,如下:
// bitstruct.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<stdlib.h>
typedef unsigned int UINT;
#define INTBITS(WIDTH) \
typedef struct \
{ \
signed ad : WIDTH; \
unsigned unused : 32 - WIDTH; \
} INT##WIDTH
int _tmain(int argc, _TCHAR* argv[])
{
UINT x;
INTBITS(12); // Now struct INT12 is available
INTBITS(14);
// Now struct INT14 is available
x = 0x00000ffe;
printf(
"x == 0x%x\n"
"12 bits signed number of x == %d\n",
x,
(reinterpret_cast<INT12*>(&x))->ad
);
x = 0x00003ffe;
printf(
"x == 0x%x\n"
"14 bits signed number of x == %d\n",
x,
(reinterpret_cast<INT14*>(&x))->ad
);
system("pause");
return 0;
}
程序的结果表明,这种方法的确运行正确。
程序的关键在于宏INTBITS,它有一个参数WIDTH,用来表示AD的位数,可以代入12,14这样的整数,不过千万不要代入12+2这样的表达式。代入不同的整数,INTBITS会定义不同的结构体,INTBITS(12)会定义名为INT12的结构体,它的位域ad代表12b的有符号补码形式整数,INTBITS(14)会定义名为INT14的结构体,它的位域ad代表14b有符号补码形式整数,其余依次类推,只要AD数据不超过32b,直接使用ad域就行。
2009年10月26日补充:在《AD补码数据和位段结构体(续)》中,使用template而不是Macro来实现代码中的位段结构体。
http://blog.sina.com.cn/s/blog_4513dde60100o6qn.html
这是调电路时遇到的问题。由12位AD传来的数据放入字长为32b的存储器里。其中存储器的数据线中低12b与AD相连,其余接地。AD数据使用12位补码表示。于是字长为32b的存储器里每个字存放的数据是由低12b的AD数据和高20b的0组成。如果再利用运行于CPU上的C程序对这些存储器中的数据进行处理,则无法直接使用。
例如,AD传送了数据-2,用12b的补码表示就是0xffe,但是在C程序中如果直接用32b的int类型来操作,就成了0xffe == 4094,两者相去甚远。只有进行一些附加的操作,比如,判断数据的11b(最低位为0b)是否等于1,若是,则将数据的高20b置1,写成代码就是:
if ((x & 0x800) != 0) x |= 0xfffff000;
我想,在C的层面上是否有更简便而灵活的操作方法。假如说我们的AD换成了4b,6b,8b,14b,16b,18b,20b等等(好像AD没有这么多类),那么上面代码中的0x800和0xfffff000就要换成相应的数值才行,虽然不很麻烦,但也有点麻烦。
那天看以前写的程序,发现位段结构体中位域都使用unsigned修饰的。我想,位域大概也可以用signed修饰吧!好像从来没有这样做过。如果能行,我们是不是找到了一种应对AD有符号补码数据的灵活方法呢?于是写了一段代码验证想法,如下:
// bitstruct.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<stdlib.h>
typedef unsigned int UINT;
#define INTBITS(WIDTH) \
typedef struct \
{ \
signed ad : WIDTH; \
unsigned unused : 32 - WIDTH; \
} INT##WIDTH
int _tmain(int argc, _TCHAR* argv[])
{
UINT x;
INTBITS(12); // Now struct INT12 is available
INTBITS(14);
// Now struct INT14 is available
x = 0x00000ffe;
printf(
"x == 0x%x\n"
"12 bits signed number of x == %d\n",
x,
(reinterpret_cast<INT12*>(&x))->ad
);
x = 0x00003ffe;
printf(
"x == 0x%x\n"
"14 bits signed number of x == %d\n",
x,
(reinterpret_cast<INT14*>(&x))->ad
);
system("pause");
return 0;
}
程序的结果表明,这种方法的确运行正确。
程序的关键在于宏INTBITS,它有一个参数WIDTH,用来表示AD的位数,可以代入12,14这样的整数,不过千万不要代入12+2这样的表达式。代入不同的整数,INTBITS会定义不同的结构体,INTBITS(12)会定义名为INT12的结构体,它的位域ad代表12b的有符号补码形式整数,INTBITS(14)会定义名为INT14的结构体,它的位域ad代表14b有符号补码形式整数,其余依次类推,只要AD数据不超过32b,直接使用ad域就行。
2009年10月26日补充:在《AD补码数据和位段结构体(续)》中,使用template而不是Macro来实现代码中的位段结构体。
相关文章推荐
- Redis源代码-数据结构Adlist双端列表
- redis源码分析之数据结构(一)链表adlist.c
- 结构体内包含位段,其数据内存分布
- 结构体内包含位段,其数据内存分布
- Linux环境下C的数据类型长度和位段结构
- redis源码系列-数据结构(adlist/ziplist/dict)
- redis源码系列-数据结构(adlist/ziplist/dict)
- 数据结构实验之链表八:Farey序列
- 数据结构(九)
- 数据结构之重写ArrayList的底层源码
- Java数据结构之图_动力节点Java学院整理
- mysqldump 只导出数据 或者 只导出表结构
- 【数据结构】——稀疏矩阵转置
- 二叉树遍历Java之美[从菜鸟到高手演变]之数据结构基础之树、二叉树
- 数据结构(四)二叉树的遍历
- 数据结构(5)之单链表的操作(补充)
- memched1.0源码阅读(2)——基础数据结构
- LINUX 下mysql导出数据、表结构
- 【数据结构与算法】内部排序之三:堆排序(含完整源码)
- 数据结构与算法简记:按层次顺序遍历和存储二叉树