Dict.CN 在线词典, 英语学习, 在线翻译

学海苦作舟,书山勤为径

留下点回忆

常用链接

统计

积分与排名

Denoise

English study

Web技术

数据压缩

一些连接

最新评论

关于C结构体bit field的跨平台的教训。

C语言的STRUCT提供了一种叫bit field的语法,可以根据需要决定成员占用某字节的从X位到Y位,例如,下面一个结构:
struct tagtest
{
   char a:4;
   char b:2;
   char c:2;
};

这个定义的含义是整个结构是一个字节长度,成员a占4位,b占2位,c占2位。这样定义以后,我们可以方便的通过设置成员的值来设置结构,而不需要进行位操作了。例如:
tagtest myTest;
myTest.a = 10;
myTest.b = 2;
myTest.c = 1;

但今天发现一个问题,就是windows系统上的和MAC上对待这个结构是不同的;现象如下:
如果在windows上这是上面的值,在MAC上得到的结构成员值为:
myTest.a = 6;myTest.b = 2;myTest.c = 2;
仔细分析之后觉得这个不是字节序的问题,因为字节序对一个字节是不起作用的,如果起作用那传输数据就麻烦了了;那么是什么问题导致的呢?
应该是编译器造成的,规律如下:
在WINDOS上,编译器认为c是字节的高位,而a是字节的低位;但MAC上正好相反了;a 是字节的低位,c是字节的低位。
紧记在心!!!

posted on 2006-09-08 14:04 笨笨 阅读(5253) 评论(27)  编辑 收藏 引用 所属分类: 调试

评论

# re: 关于C结构体bit field的跨平台的教训。 2006-09-11 08:38 cmdn

这应该就是大端和小端的问题吧!  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-09-11 08:53 笨笨

如果你说是,那么我说你错了  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-09-11 08:54 笨笨

仔细看文章  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-09-13 16:46 Perry

C语言没有规定位段的存储顺序,因此是编译器相关的,这个好像在不少书上都强调过记得

但是如果在同一个程序里只使用.运算符操作应该是不会有问题的啊,只会在把各位段作为整体(例如一个位段和整数的union)操作,或者在windows下写入文件再在mac下读出来才会有你说的情况发生罢?  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-09-13 21:15 笨笨

不是的,测试结果告诉我,在两种操作系统中即使为该结构体设置同样的值,对应的成员值是不一样的。  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-09-18 20:43 Perry

不懂你的意思
“即使为该结构体设置同样的值,对应的成员值是不一样的”
你是说如果赋值
myTest.a = 10;
myTest.b = 2;
myTest.c = 1;
会得到结果
myTest.a == 6;myTest.b == 2;myTest.c == 2;

这显然是不可能的!  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-09-19 09:16 笨笨

可能是我描述有问题,或者你的理解有问题,呵呵。
当然,设置和取值是在不同的操作系统上。例如:
myTest.a = 10;
myTest.b = 2;
myTest.c = 1;
16进制是0X64
在WINDOWS上,然后将该结构,发送到MAC 上
这个结构的缓冲区仍然是0X64,我有一个缓冲区保存它,例如:
char buf[1];
buf[0] = 0X64;
然后强制转换,tagtest * pMyTest = (tagtest *)buf;
这个时候,各成员的值是:
myTest.a == 6;myTest.b == 2;myTest.c == 2;
如果再不明白就没有办法了。

不要总是说impossible!  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-09-21 09:20 bobby567

Perry说可能与编绎器有关系,请问你在WINDOWS和MAC上是使用的同一编绎器吗???
  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-09-21 10:20 笨笨

文章中已经提到是和编绎器有关系的。  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-09-21 11:19 Perry

请注意我的第一次回复
或者在windows下写入文件再在mac下读出来才会有你说的情况发生罢?
你的回答是:不是的

或许你并不是写文件,而是网络传,但我想你应该可以明白我的意思  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-09-22 10:19 笨笨

你这里没有完全说明白,我怕你隐含了某些东西。其实我想强调的是,这不是网络字节序的问题。  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-10-06 21:46 路过

就跟编译器有关吧,跟操作系统有啥关系  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-10-07 16:25 笨笨

严格的说是和操作系统没有关系,但是某些编译器只能在某些操作系统上运行,所以和操作系统有间接的关系。  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-11-15 12:09 qzq

是大端小端序的问题(和CPU架构有关)。


BYTE data[] = {0x12, 0x34};
Uint16 value = *(Uint16*)data;
struct tagtest
{
char a:4;
char b:2;
char c:2;
};
tagtest* tag = (tagtest*)data;
如果大端序, value == 0x1234, 即 Uint16 保存时先先保存高字节。
tag->a == 1,即位域保存时先保存在高比特。

如果小端序, value == 0x3412, 即 Uint16 保存时先保存低字节。
tag->a == 2, 即位域保存时先保存在低比特。





  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-11-17 09:26 笨笨

你高错了吧  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-11-17 09:26 笨笨

我说的可以是一个字节啊  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-12-06 16:31 wwxxdd1982

字节序说的是多于一个字节以上的字节在内存中的存储顺序!!!!
bit field指的bit!!!!根本扯不到一起

我只想说如果是在连续的win 和 mac都在连续的内存空间内你说的
现象是不会发生的!如果在不连续的空间内就很有可能了。

C的标准语法里并没有说bit field 是连续存储的哦~~~~
  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-12-13 09:08 qzq


大端小端序不光是字节序,还包括比特序,这个是和CPU架构有关的。编译器只不过是配合CPU架构,所以不同CPU架构的表现不同,PC、MAC 上的正好不同,x86是小端,MAC的CPU是大端序。
  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2006-12-13 21:00 windcsn

qzq能给个介绍关于bit序的地方吗?说实话,我可是第一次听到这个.和CPU有关不假,可从来么有听说过CPU的字节上的bit顺序不同,指教  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2007-06-01 10:07 暗暗

在WINDOS上,编译器认为c是字节的高位,而a是字节的低位;但MAC上正好相反了;a 是字节的低位,c是字节的低位。

you笔误  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2007-06-01 14:59 暗暗

应该是X86和MAC体系的不同吧
X86:
x86的位是从右到左的填入,在这里就是0110 1010了
其中a就是1010,b是10c是10
MAC:
MAC的是从左到右的填入,读的时候当然也把写的时候当成从左到右
所以先天在这里就成了a为0110,b为10,c为10
也就是a为6,b为2,c为2。
这跟大端小端没关系,大端小端说的是字节间的关系。
这里是字节内部的位的排列顺序,对吧
谢谢lz,我也懂了,嘿嘿  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2007-09-13 21:51 蚂蚁终结者

不错,以前只知道bit field不好移植,今天算是见到实际例子了  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2008-02-14 17:01 狂.玫瑰

看到暗暗的回复才有如梦初醒的感觉,感谢楼主给出的实际例子.  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2008-04-13 13:13 树欲静而风不止

看一看windows 的编译器:
mytest.a=10;
00401024 mov al,byte ptr [mytest]
00401027 and al,0F0h
00401029 or al,0Ah
0040102B mov byte ptr [mytest],al
mytest.b=2;
0040102E mov al,byte ptr [mytest]
00401031 and al,0CFh
00401033 or al,20h
00401035 mov byte ptr [mytest],al
mytest.c=1;
00401038 mov al,byte ptr [mytest]
0040103B and al,3Fh
0040103D or al,40h
0040103F mov byte ptr [mytest],al
先定义的域在windows 上被翻译为字节的低bit.
Mac 我没有试,想必是被编译器把先定义的bit看成了
高bit, 我们没有直接进行位操作,是编译器为我们做了。
笨笨说的是对的。  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2012-06-18 10:31 scorpioo

可以参考一下这个:
How Endianness Effects Bitfield Packing
http://mjfrazer.org/mjfrazer/bitfields/  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2016-03-28 19:54 test

原则1:无论cpu架构,结构体bit-field成员,bit地址是递增的。
原则2:bitfields的每个比特,bigendian中,MSB(人类读的最高有效位)在低地址, little endian,则MSB在高地址。
所以:
myTest.a = 10;
myTest.b = 2;
myTest.c = 1;

在intel上,MSB在高位
a=10(bit3~0=1010),b=2(bit5~4=10),c=1(bit7~6=01)
合起来是含义(人类读法):bit7~0=0x6A。

在mac上,MSB放在低地址:
a=10=1010 B同样使用低bit3~0,不过高位(MSB)在bit0,写作bit0~3 =1010
b=2 = 10 B ,同样使用较高地址bit 4~5,不过高位在bit4,bit4~5写作10
c=1 = 01 B,同样使用最高地址bit6和7,高位在bit6,bit6,7 写作 01
于是,含义(人类读法):bit0~7=10101001 B=0xA5  回复  更多评论   

# re: 关于C结构体bit field的跨平台的教训。 2016-03-28 19:59 test

原则1:无论cpu架构,结构体bit-field成员,bit地址是递增的。
原则2:bitfields的每个比特,bigendian中,MSB(人类读的最高有效位)在低地址, little endian,则MSB在高地址。
所以:
myTest.a = 10;
myTest.b = 2;
myTest.c = 1;

在intel上,MSB在高位
a=10(bit3~0=1010),b=2(bit5~4=10),c=1(bit7~6=01)
合起来是含义(人类读法):bit7~0=01101010=0x6A。

在mac上,MSB放在低地址:
a=10=1010 B同样使用低bit3~0,不过高位(MSB)在bit0,写作bit0~3 =1010
b=2 = 10 B ,同样使用较高地址bit 4~5,不过高位在bit4,bit4~5写作10
c=1 = 01 B,同样使用最高地址bit6和7,高位在bit6,bit6,7 写作 01
于是,含义(人类读法):bit0~7=10101001 B=0xA9  回复  更多评论   


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理