我刚刚发现bitflags的喜悦。 我有关于“最佳做法”关于C.使用bitflags的我学会了从不同的例子我在网上找到,但仍然有问题,一切的几个问题。
为了节省空间,我使用的是单个32位整数字段在一个结构( A->flag
)来表示几个不同组布尔属性。 总之,20个不同的位#define
d。 其中有些是真正存在/不存在标志(STORAGE-内部与储存器外部的)。 其他具有两个以上的值(例如相互排斥的集合的格式:格式A,FORMAT-B,FORMAT-C)。 我已设定的特定位(并同时关闭互斥位)定义的宏。 如果位的特定组合的标志设置我还定义了测试宏。
但是,什么是失去了在上述方法是最好的枚举捕获标志的具体分组。 对于写功能,我想用枚举(例如,存储,类型和格式-TYPE),使函数定义好看。 我希望用枚举只为传递参数和#define的宏设置和测试标志。
(a)中如何定义标志( A->flag
),其为32位整数中的便携式的方式(在32位/ 64位平台)?
(二)我应该担心如何潜力大小的差异A->flag
对#define
d常量与枚举存储?
(三)我是不是做事情过于复杂,这意味着我应该只是坚持使用#define
d常数传递参数为普通int
S' 我应该在这一切担心还有什么呢?
我的关节不好的问题道歉。 它反映了我对潜在问题的无知。
正如其他人所说,你的问题(一)是通过解析<stdint.h>
,要么uint32_t
或uint_least32_t
(如果你要担心的具有36位字巴勒斯大型机)。 需要注意的是MSVC不支持C99,但@DigitalRoss显示可以在其中获得一个合适的标题与MSVC使用。
您的问题,(b)是不是一个问题; C的温度将安全型转换为你,如果它是必要的,但它可能甚至没有必要。
最令人关注的领域是(C),特别是格式的子场。 目前,3个值是有效的。 可以通过分配3个比特,并要求3位字段是值1的一个,2个或4(任何其他值是因为过多或过少的比特的设置无效)处理这个问题。 或者你可以分配一个2位数,并指定0或3(或者,如果你真的想要,1或2)是无效的。 第一种方法使用一个以上位(目前还不是因为你只使用32 20位的问题),但是是一个纯粹的位标志的做法。
当写函数调用,也没有特别的问题写:
some_function(FORMAT_A | STORAGE_INTERNAL, ...);
这将工作FORMAT_A是否使用#define或枚举(只要您正确指定枚举值)。 被调用的代码应检查调用者是否有浓度时隔写道:
some_function(FORMAT_A | FORMAT_B, ...);
但是,这是一个内部检查模块担心,并不是对模块担心的用户进行检查。
如果人们将要切换的位flags
周围有很多成员,用于设置和取消格式字段宏可能是有益的。 有些人可能会争辩说,任何纯布尔领域几乎没有需要它,但(我会同情)。 这可能是最好的治疗flags
成员作为不透明,并提供“功能”(或宏)来获取或设置所有字段。 的人更可能出错的地方,不太会出问题。
考虑使用位字段是否为你的作品。 我的经验是,它们会导致大码并不见得很高效的代码; 因人而异。
嗯......没有什么很明确的在这里,至今。
- 因为这些保证是可见的调试器,其中的#define值不是我会用枚举的一切。
- 我可能不会提供宏来获取或设置位,但我有时一个残酷的人。
- 我将提供关于如何设置标志字段的格式部分指导,可能会提供一个宏来做到这一点。
像这样的,也许:
enum { ..., FORMAT_A = 0x0010, FORMAT_B = 0x0020, FORMAT_C = 0x0040, ... };
enum { FORMAT_MASK = FORMAT_A | FORMAT_B | FORMAT_C };
#define SET_FORMAT(flag, newval) (((flag) & ~FORMAT_MASK) | (newval))
#define GET_FORMAT(flag) ((flag) & FORMAT_MASK)
SET_FORMAT
如果准确地使用,但可怕的,如果滥用是安全的。 宏的一个好处是,你可以用,如果有必要彻底验证的东西功能替换它们; 这种运作良好,如果人们使用宏一致。
还有就是旨在解决这一确切的问题(一),但由于某种原因,微软没有实现它C99头。 幸运的是, 你可以得到<stdint.h>
的Microsoft Windows这里 。 所有其他平台将已经拥有了它。 的32位int类型是uint32_t
和int32_t
。 这些也都在8,16,和64位的口味。
所以,这需要照顾(一)。
(b)和(c)是一种同样的问题的。 我们确实做出假设,每当我们开发的东西。 你认为是c将可用。 您认为<stdint.h>
可以发现某处。 你总是可以假设int
至少是16位,现在一个> = 32位的假设是相当合理的。
在一般情况下,你应该尝试编写符合不依赖于布局方案,但他们会做出字长的假设。 你应该担心在算法级性能,也就是我写的东西是二次,多项式,指数?
你不应该担心在操作级别的表现,直到(a)您注意到性能滞后,以及(b)你具有一定轮廓的程序。 你需要得到你的工作没有陷入泥淖担心单独操作完成。 :-)
哦,我要补充的是你特别不必担心低级别运行性能,当你用C首先编写程序 。 C是贴近的金属细末为快速-AS-可能的语言。 我们经常写东西,在PHP,Python和Ruby,或口齿不清,因为我们希望有一个强大的语言和CPU的是如此之快,这些天来,我们可以用一个完整的解释蒙混过关,别提位玩弄字的一个不完美的选择-length欢声笑语。 :-)
您可以使用位字段,让编译器做的位操作。 例如:
struct PropertySet {
unsigned internal_storage : 1;
unsigned format : 4;
};
int main(void) {
struct PropertySet x;
struct PropertySet y[10]; /* array of structures containing bit-fields */
if (x.internal_storage) x.format |= 2;
if (y[2].internal_storage) y[2].format |= 2;
return 0;
}
编辑补充结构的阵列
对于问题一,如果你使用的是C99(你可能正在使用它),你可以使用uint32_t
预定义类型(或者,如果没有预先定义,它可以在发现stdint.h
头文件)。
至于(三):如果你的枚举正确定义,你应该能够将其作为参数传递不会有问题。 有几件事情要考虑:
- 枚举存储往往是具体的编译器,所以这取决于你在做什么样的发展(你不提,如果是Windows还是Linux与嵌入式Linux嵌入式:)对),你可能要访问编译器选项,枚举存储到确保没有任何问题存在。 我大体上同意编译器应该适当地投你列举上述共识 - 但它的东西要注意的。
- 在你正在做嵌入式的工作的情况下,许多静态的质量检查程序,例如PC林特会“汪汪”如果你开始使用枚举,#定义,和位域太聪明了。 如果你正在做开发,将需要经过任何质量门,这可能是东西要记住。 事实上,如果你找一个支持位域trig的一些汽车标准(如MISRA-C)得到彻头彻尾的烦躁。
- “我刚刚发现bitflags的喜悦。” 我同意你的 - 我觉得他们非常有用。
我添加了注释上述每个答案。 我觉得我有一些清晰。 这似乎是枚举清洁,因为它在调试器中显示出来,并保持场分开。 宏可用于设置和获取价值。
我也读了枚举存储为小整数 - 这是我的理解,是不是与布尔测试,这些将开始最右边的位来peroformed的问题。 但是,可以枚举用于存储大的整数(1 << 21)??
再次感谢大家。 我已经学会了,比我前两天多!
〜拉斯