- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我使用嵌入式东西 (PIC),在我见过的所有 C 代码中,如果函数采用多个标志或少量枚举值,它是作为手工制作的 int 位掩码完成的,就像这样:
/* first flag */
#define MY_FIRST_FLAG (1 << 0)
/* second flag */
#define MY_SECOND_FLAG (1 << 1)
/*
* some param that could have three variants
*/
#define __MY_TRISTATE_OFFSET 2
#define __MY_TRISTATE_MASK (0x03 << __MY_TRISTATE_OFFSET)
#define MY_TRISTATE_ONE (0 << __MY_TRISTATE_OFFSET)
#define MY_TRISTATE_TWO (1 << __MY_TRISTATE_OFFSET)
#define MY_TRISTATE_THREE (2 << __MY_TRISTATE_OFFSET)
/* third flag */
#define MY_THIRD_FLAG (1 << 4)
void my_func(int opts)
{
if (opts & MY_FIRST_FLAG){
/* ... */
}
switch (opts & __MY_TRISTATE_MASK){
case MY_TRISTATE_ONE:
/* ... */
break;
case MY_TRISTATE_TWO:
/* ... */
break;
case MY_TRISTATE_THREE:
/* ... */
break;
default:
/* error! */
break;
}
/* ... */
}
但我不太喜欢这种“极客”方式:
my_func(MY_TRISTATE_ONE | MY_TRISTATE_TWO);
它会编译。 这种方法的唯一优点是二进制兼容性:数据在所有平台上以完全相同的方式组织,因此,不同的设备/程序可以使用此接口(interface)进行通信。但是,对我来说,这几乎总是出于担忧:大多数代码只在一个特定的设备上工作,不需要保持与其他世界的二进制兼容性。
所以,对我来说,定义一个小结构看起来要好得多:
enum my_tristate_e {
MY_TRISTATE_ONE,
MY_TRISTATE_TWO,
MY_TRISTATE_THREE,
};
struct my_func_opts_s {
unsigned my_first_flag : 1;
unsigned my_second_flag : 1;
enum my_tristate_e my_tristate : 2;
unsigned my_third_flag : 1;
};
void my_func(struct my_func_opts_s opts)
{
if (opts.my_first_flag){
/* ... */
}
switch (opts.my_tristate){
case MY_TRISTATE_ONE:
/* ... */
break;
case MY_TRISTATE_TWO:
/* ... */
break;
case MY_TRISTATE_THREE:
/* ... */
break;
default:
/* error! */
break;
}
/* ... */
}
这种方法的优点:
my_func
另一个结构(比如,我们有另一个带有另一个函数选项的结构),如果我们尝试编译器会产生错误;2
更改为 3
,编译器会警告我们字段太窄;同样,如果我们需要程序是二进制兼容的,这种方法将不起作用,但它几乎总是令人担忧。
有人可能会争辩说调用该函数看起来太庞大了:在 int 标志的情况下,我们有:
my_func(MY_TRISTATE_TWO | MY_FIRST_FLAG);
但是在结构的情况下:
my_func2((struct my_func_opts_s){
.my_first_flag = true,
.my_tristate = MY_TRISTATE_TWO,
});
但无论如何,在我看来,强类型安全值得输入。而且,毕竟,有时候我什至更喜欢第二种方式,因为这段代码的 self 文档化程度更高。
我已经检查了两种情况下生成的 MIPS 反汇编(好吧,我不得不稍微更改函数以使它们执行某些操作,否则它们会被编译器优化掉),并且生成的代码几乎相同(优化是-Os
这在嵌入式世界中很常见):
但是,这种方法从未(或几乎从未)使用过。为什么?我错过了什么重要的事情吗?
最佳答案
在 struct
中使用位域的一个缺点是您不能直接在函数调用处写入标志,除非您可以访问 C99 中的“复合文字”。
假设您有一个如下所示的位域:
struct bit_field {
unsigned int a:1;
unsigned int b:1;
unsigned int c:1;
unsigned int d:1;
};
还有一个使用像这样声明的位域的函数:
void use_bit_field(struct bit_field a);
如果您使用 C99 编写,您可以像以前那样编写函数调用:
use_bit_field((struct bit_field){
.a = 1,
.b = 0,
.c = 1,
.d = 0
});
看起来很不错!但是为了让它工作,我们需要能够使用“复合文字”,这是 C99 的一个特性。不幸的是,您可能已经知道 C99 不像 C89 那样广泛可用。
没有接触过C99的人必须这样写函数调用:
struct bit_field bits = {
1, 1, 0, 1 // EDIT: Initializing the struct step by step is alot less error prone (mentioned in the comments).
};
/* ... */
use_bit_field(bits);
有些人会争辩说远不如:
use_bit_field(BITFIELD_A | BITFIELD_B | BITFIELD_D);
但这当然只是一个偏好问题。
另一个缺点是您失去了在位域上执行位操作的机会。
你不能写:
if (bit_field1 & bit_field2)
检查两个位域是否都打开了相同的位。你必须写一个丑陋的类型转换:
if (*(int8_t *)&bit_field1 & *(int8_t *)&bit_field2)
这些是我能想到的缺点。我个人仍然认为在 struct
中定义位域是更好的方法。
关于c - 将几个标志和小枚举作为函数参数传递 : hand-made int bitmasks or small struct?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25832224/
关于 PHP documentation关于 JSON,它提到了位掩码这个词。维基百科将其定义为面具。我不明白位掩码或掩码或它们是如何有用的。有人可以使用外行的术语而不是行话来解释这些术语吗? 最佳答
阅读销售点系统的文档,这里是他们给出的 mask 示例,该 mask 应该告诉您选择了哪些座位。我无法弄清楚这一点。我完全理解位掩码。这个例子是不是错了? 函数 该系统变量是一个八个字符的字符串,其中
我试图从一个二进制文件中取出四个字节,并将它们转换成一个位掩码,代表数据的零和元数据的 1。 我假设我需要通过将它们组合在一起来将它们转换为 int,然后通过移位来确定是否设置了位位置。 我无法弄清楚
这是我的合作伙伴想出的代码,但出于某种原因,我无法联系到他,问他应该如何工作。我现在已经经历了很多次,但似乎无法得到我应该得到的答案。 /** * bitMask - Generate a mask
[旗帜] public enum ShowProductOn : short { HomePage = 1, SalesPage = 2, NewsLetter = 4 };
BufferedImage 类实现 Transparency,它具有三个值: OPAQUE表示不透明。 TRANSLUCENT 表示每个像素的 Alpha 值都在 0 到 1 之间。 BITMASK表
我对这个任务有疑问。 http://www.spoj.com/problems/LINEUP/看起来很简单,但我的解决方案失败了。我得到错误的结果。任何人都可以帮忙弄清楚吗?非常感谢您的帮助。 :-)
我希望能够在 Swift 中正确读取 NSUnderlineStyle 的值。 它比看起来更复杂。 首先,快速回顾一下。 NSUnderlineStyle 是具有以下值的枚举: NSUnderline
我试图避免英雄和硬币之间的碰撞,但不是英雄和草地之间的碰撞。一旦我将碰撞位掩码应用于 Hero,我的 Hero 就会穿过所有东西。我希望它穿过硬币而不是穿过草地。这是代码,有什么想法吗? let HE
所以我决定创建一个控制台类来替代 std::cout console = GetStdHandle(STD_OUTPUT_HANDLE); this->current_color =
我正在研究基于位板的国际象棋引擎,其中一项大量执行的操作是设置/清除无符号 64 位整数中的位。由于我不太了解哪些代码可以在某些处理器上“更快”地运行,因此我无法完全理解这一点。 设置和清除位是一个非
我正在尝试使用 numpy 将几个掩码( bool 数组)转换为一个位掩码,虽然理论上可行,但我觉得我做了太多操作。 例如创建我使用的位掩码: import numpy as np flags = [
例子 self.accessibilityTraits |= UIAccessibilityTraitAdjustable; 添加了 UIAccessibilityTraitAdjustable 选项
我开始使用 ini_get_all 函数来检索共享主机服务器上的所有配置选项。最后我得到了这个数组 block : [allow_call_time_pass_reference] => Array
目前我将一组项目的组合存储为单个整数(位掩码值),如下例所示: 示例: 1 - Orange 2 - Banana 4 - Cherry 8 - Apple 然后如果用户选择Orange (1) 和A
我正在使用 Python 编程并使用 SQLAlchemy 来存储营业时间。 营业时间由三部分组成: 星期几以二进制形式存储为位掩码 营业时间, 企业关闭的时间。 位掩码是这样工作的。有 7 个数字,
我对一种“扩展位”的快速方法很感兴趣,它可以定义如下: 设 B 是一个有 n 位的二进制数,即 B\in {0,1}^n 设P为B中所有1/true位的位置,即1 A 给定 B,使得 Ap[j] ==
我使用嵌入式东西 (PIC),在我见过的所有 C 代码中,如果函数采用多个标志或少量枚举值,它是作为手工制作的 int 位掩码完成的,就像这样: /* first flag */ #define M
所以,最近开始学习iOS开发和Objective-C,主要是利用斯坦福在iTunes U上的免费类(class)。 我最终偶然发现了位掩码,这是 iOS API 中广泛使用但我不是很熟悉的东西。我已经
我想将不同长度的二维数组存储为 AwkwardArray,将它们存储为 Parquet,然后再次访问它们。 问题是,从 Parquet 加载后,格式是 BitMaskedArray并且访问性能有点慢。
我是一名优秀的程序员,十分优秀!