ISO/IEC 14882:2003: 9.6 Bit-fields [class.bit]

  1. A member-declarator of the form identifieropt : constant-expression specifies a bit-field; its length is set off from the bit-field name by a colon. The bit-field attribute is not part of the type of the class member. The constant-expression shall be an integral constant-expression with a value greater than or equal to zero. The constant-expression may be larger than the number of bits in the object representation (3.9) of the bit-field’s type; in such cases the extra bits are used as padding bits and do not participate in the value representation (3.9) of the bit-field. Allocation of bit-fields within a class object is implementation-defined. Alignment of bit-fields is implementation-defined. Bit-fields are packed into some addressable allocation unit. [Note: bit-fields straddle allocation units on some machines and not on others. Bit-fields are assigned right-to-left on some machines, left-to-right on others. ]
  2. A declaration for a bit-field that omits the identifier declares an unnamed bit-field. Unnamed bit-fields are not members and cannot be initialized. [Note: an unnamed bit-field is useful for padding to conform to externally-imposed layouts. ] As a special case, an unnamed bit-field with a width of zero specifies alignment of the next bit-field at an allocation unit boundary. Only when declaring an unnamed bit-field may the constant-expression be a value equal to zero.
  3. A bit-field shall not be a static member. A bit-field shall have integral or enumeration type (3.9.1). It is implementation-defined whether a plain (neither explicitly signed nor unsigned) char, short, int or long bit-field is signed or unsigned. A bool value can successfully be stored in a bit-field of any nonzero size. The address-of operator & shall not be applied to a bit-field, so there are no pointers to bit-fields. A non-const reference shall not be bound to a bit-field (8.5.3). [Note: if the initializer for a reference of type const T& is an lvalue that refers to a bit-field, the reference is bound to a temporary initialized to hold the value of the bit-field; the reference is not bound to the bit-field directly. See 8.5.3. ]
  4. If the value true or false is stored into a bit-field of type bool of any size (including a one bit bitfield), the original bool value and the value of the bit-field shall compare equal. If the value of an enumerator is stored into a bit-field of the same enumeration type and the number of bits in the bit-field is large enough to hold all the values of that enumeration type, the original enumerator value and the value of the bit-field shall compare equal.

最近在64bit IOS上遇到一个问题, 发现bit field的数据不对. 这个bit field是一个data struct, 在host(win32)上生成. 运行时候发现IOS取的值不对.

比如

//IOS 32
struct
{
//allocation unit 1
int a : ;
int b : ;//12bit
int c : ; //28bit
int d : ; //4 bit allocation uint 1, 4 bit allocation unit 2
int e : ; //20 bit in allocation unit 2
}; //IOS 64
struct
{
//allocation unit 1
int a : ;
int b : ;//12bit
int c : ; //28bit
//allocation unit 2
int d : ; //8 bit
int e : ; //24 bit
};

在IOS的32位上, d会横跨两个allocation uint, 而在IOS的64位上, d直接从第二个allocation unit上从新开始. clang在编译32位跟64位时的处理方式不一样,不知道是不是bug. 就算它是clang的bug, 但仍然是遵循标准的.因为C++标准说了可以这样.

根据C++标准, 这个是implementation defined behavior, 编译器可以选择横跨也可以不横跨, 都可以.

在host(win32)上的打包程序, MSVC也是横跨方式, 与clang处理32 bit IOS的方式一致. 所以(凑巧)host生成的数据可以在IOS32上面使用, 可能大多数编译器都以横跨方式处理bitfields吧.

解决方法是:将a,b,c对齐到32bit的整数, 这样强制d从新的allocation unit开始, 没有横跨的问题, 对于IOS32位和IOS64位都有效.

//shared disk data

//IOS 32
struct
{
//allocation unit 1
int a : ; //4bit
int b : ; //12bit
int c : ; //32bit
//allocation unit 2
int d : ; //8 bit
int e : ; //24 bit
}; //IOS 64
struct
{
//allocation unit 1
int a : ; //4bit
int b : ; //12bit
int c : ; //32bit
//allocation unit 2
int d : ; //8 bit
int e : ; //24 bit
};

另外, IOS 64bit的额外参考: 对齐等等其他因素

https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaTouch64BitGuide/ConvertingYourAppto64-Bit/ConvertingYourAppto64-Bit.html

https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaTouch64BitGuide/Major64-BitChanges/Major64-BitChanges.html

bitfield用在game data里面, 如果多平台共享的同一份数据话, 就有类似上面的的问题. 甚至顺序也有可能不一样(left-to-right/right-to-left), 所以blade里面没有用过. 而公司的代码用的地方非常多.

公司的代码虽然是跨平台的, 但是之前是每个平台都有不同的数据, 现在IOS 32/64要共享同一份数据, 才会有上面的问题. 这个是历史的原因.毕竟积累了近20年的代码. 注重代码和技术积累, 这样的公司才靠谱.

另外公司有自己的编译器, 最好的方式是在编译器上直接解决bitfield的straddle和left-to-right/right-to-left的问题. 这样上面的代码就不用关心这些琐碎的细节了.

个人的观点是每个平台使用通用的数据最好.

以下内容摘自我的另一博客(http://hi.baidu.com/crazii_chn/item/62705798f8a76bd91b49dfd8):

一般来说, 需要根据每一种目标平台, 各生成一份对应的数据.
这样做的好处是每个平台的数据可以根据目标特性做调整.比如移动平台的场景规模/质量和数据量一般都相对要小.
由于每种CPU的数据处理特性(cache line, alignment, SIMD指令集)可能都不一样,所以需要做特别的处理.

对于数据的格式,有两种做法, 第一是每个平台的数据包格式不一样, 第二是种是使用统一的格式, 也就是说尽管每个目标平台都有不同的一个数据包(因目标规模而定), 但理论上某个平台可以正常加载其他所有平台的数据包.
而第一种则不同, 各个平台的数据格式不一样, 比如一个struct的成员对齐不同, 那么序列化后的数据会有大小和偏移量的差别.

第一种方式不用特别考虑数据对齐等等问题, 但是要生成和维护不同目标平台下的数据包和工具, 虽然维护成本相对较低,但是如果工具很多的时候也很繁琐.
第二种方式需要在代码中考虑对齐等等因素, 保证一个数据包可以被所有的平台加载, 这么做可能也很繁琐,需要特别小心,并经过完整的数据测试.

这里有一个android下x86和arm的结构对齐的处理 (4.1 Forced Memory Alignment):
http://software.intel.com/en-us/articles/android-application-development-and-optimization-on-the-intel-atom-platform
参考http://software.intel.com/en-us/blogs/2011/08/18/understanding-x86-vs-arm-memory-alignment-on-android/
比如上面第一个链接中使用的"-malign-double" GCC参数, 强制8字节的数据对齐的8字节边界.保证同一份数据可以被不同的CPU正常加载. 第二个链接使用的是__attribute__((aligned(n))), 来强制数据成员的对齐.

我所在的公司使用的是第一种方式. 第一种方式的问题在于同一个OS也有不同的target CPU(platform), 这样会出现对于android平台, x86有一份数据, 而arm有另外一份数据. 所以个人倾向于第二种方式, 除了上文链接中的方式以外, 也可以强制不读写struct, 只读写原子数据, 把一个struct的成员逐个单独读写.

如何保证数据能够通用呢? 严格按照C/C++标准来做. 如果是implementation defined或者unspecified的定义, 那么就规避, 不要使用, 比如上面的那个例子. undefined behavior更不能用. 这样在host编译出的data-tools, 处理数据的方式与target上的executables处理数据的方式一致, 能够保证host上打包生成的同一份数据, 在所有平台上都可以用.

[工作积累] bitfield的更多相关文章

  1. [工作积累] Google/Amazon平台的各种坑

    所谓坑, 就是文档中没有标明的特别需要处理的细节, 工作中会被无故的卡住各种令人恼火的问题. 包括系统级的bug和没有文档化的限制. 继Android的各种坑后, 现在做Amazon平台, 遇到的坑很 ...

  2. [工作积累] 32bit to 64bit: array index underflow

    先贴一段C++标准(ISO/IEC 14882:2003): 5.2.1 Subscripting: 1 A postfix expression followed by an expression ...

  3. [工作积累] GCC 4.6 new[] operator内存对齐的BUG

    对于用户没有定义dctor(包括其所有成员)的类来说, new CLASS[n] 可能会直接请求sizeof(CLASS)*n的空间. 而带有dctor的 类, 因为delete[]的时候要逐个调用析 ...

  4. [工作积累] UE4 并行渲染的同步 - Sync between FParallelCommandListSet & FRHICommandListImmediate calls

    UE4 的渲染分为两个模式1.编辑器是同步绘制的 2.游戏里是FParallelCommandListSet并行派发的. mesh渲染也分两类,static mesh 使用TStaticMeshDra ...

  5. [工作积累] D3D10+ 中 Pixel Shader 的input semantic和参数顺序

    由于semantic的使用,我们有理由相信 vertex shader的output 和 pixel shader的input是按照semantic来匹配的,而跟传入顺序无关.印象dx9时代是这样. ...

  6. [工作积累] shadow map问题汇总

    1.基本问题和相关 Common Techniques to Improve Shadow Depth Maps: https://msdn.microsoft.com/en-us/library/w ...

  7. linux-日常工作积累

    Linux常用命令之envsubst https://blog.csdn.net/banche163/article/details/101369495 Linux中的EAGAIN含义 https:/ ...

  8. HAL层Camera模块Dump图片--工作积累

    Camera的raw data一般都是YUV420的格式,数据的特点是: YUV 4:2:0采样,每四个Y共用一组UV分量 YUV420格式: 先Y,后V,中间是U.其中的Y是w * h,U和V是w/ ...

  9. JS工作积累

    /* * YYYY-MM-DD类型的字符串日期比较 * */ String.prototype.compareAsDate=function(dateStr){//prototype原型方法 var ...

随机推荐

  1. DevExpress 中 WaitForm 使用

    第一步: 在程序中拖入: splashScreenManager1 控件 在需要处理的地方 使用以下语句来打开 WaitForm窗体(当然需要在 splashScreenManager1控件中绑定一个 ...

  2. Web Service 和WCF的比较

    Web Service 的工作原理 Web Service也叫XML Web Service WebService是一种可以接收从Internet或者Intranet上的其它系统中传递过来的请求,轻量 ...

  3. Python自然语言工具包(NLTK)入门

    在本期文章中,小生向您介绍了自然语言工具包(Natural Language Toolkit),它是一个将学术语言技术应用于文本数据集的 Python 库.称为“文本处理”的程序设计是其基本功能:更深 ...

  4. XAML(2) - 依赖属性

    3.依赖属性 在用WPF编程时,常常会遇到"依赖属性"这个术语.WPF元素是带有方法,属性和事件的类.WPF元素的几乎每个属性都是依赖属性, 这是什么意思?依赖属性可以依赖其他输入 ...

  5. 利用HttpModule开发asp.net页面、ashx等访问时session失效的统一处理入口

    web程序时,当使用session时总会出现失效而报“未将对象引用设置到对象的实例”的http 500错误,本人比较懒,不想每个地方都用try catch处理,就找到个用httpModule统一处理的 ...

  6. Spring IOC 方式结合TESTGN测试用例,测试简单java的命令模式

    java命令模式: 可以命令("请求")封装成一个对象,一个命令对象通过在特定的接收着上绑定一组动作来封装一个请求.命令对象直接把执行动作和接收者包进对象中,只对外暴露出执行方法的 ...

  7. 基于AppCan MAS系统,如何轻松实现移动应用数据服务?

    完成一个移动应用开发,前端提供页面展示,当它要与一些业务系统进行交互,又该如何实现呢?2016AppCan移动开发者大会上,AppCan前端开发经理杨庆,分享了AppCan轻松实现移动应用数据服务的方 ...

  8. poj 2887 Big String

    题目连接 http://poj.org/problem?id=2887 Big String Description You are given a string and supposed to do ...

  9. 2天驾驭DIV+CSS (实战篇)(转)

     这是去年看到的一片文章,感觉在我的学习中,有不少的影响.于是把它分享给想很快了解css的兄弟们.本文是实战篇. 基础篇[知识一] “DIV+CSS” 的叫法是不准确的[知识二] “DIV+CSS” ...

  10. JavaScript高级程序设计之表单基础

    A FORM <form id='form' action='http://a-response-url' method="post"> <!--maxlengt ...