状态标志是如何表示的,以及如何使用位“或”来处理位标志
How are state flags represented and how bitwise OR is used to work with bit flags?
如果我们打开一个文件进行读取,我们可以定义一个或多个状态标志,例如:ios::out
和ios::out | iso::app
我读过比特OR,以及它如何"合并"两个比特集,
例如:1010|0111=1111
话虽如此,但我不明白当我们使用ifstream.open(filename, stateflagA | stateflagB | stateflagC)
等方法时,它是如何在"幕后"工作的。
有人能详细说明这些州旗的内部工作原理及其记忆表示吗?
编辑:为了更加强调我试图理解的内容(如果有帮助的话),我假设open方法可以接收一个或多个状态标志作为签名中的独立参数,而不是由逐位or分隔,所以我想了解在组合多个标志时,逐位or是如何对这些状态标志进行操作以产生不同的最终状态的,因此,我只能对一个状态标志或一组状态标志使用一个参数。即:
ifstream.open(filename, stateflagA | stateflagB | stateflagC)
而非
ifstream.open(filename, stateflagA , stateflagB , stateflagC)
位标志的表示方式与所有整数值的表示方式完全相同。使它们成为"标志"的是程序对其值的解释。
位标志用于小型值集的紧凑表示。为每个值分配一个位索引。将该索引处的位设置为1
的所有整数解释为包括相应成员的集合。
考虑一个小例子:假设我们需要表示一组三种颜色——红色、绿色和蓝色。我们给红色赋值为零,给绿色赋值为1,给蓝色赋值为2。这对应于以下表示:
BINARY DECIMAL COLOR
------ ------- -----
001 1 Red
010 2 Green
100 4 Blue
请注意,每个标志都是二的幂。这是二进制数的一个特性,它的单个位设置为1
。以下是它在C++中的样子:
enum Color {
Red = 1 << 0
, Green = 1 << 1
, Blue = 1 << 2
};
CCD_ 6是构造在位置n
处的单个比特被设置为1
的整数的标准方式。
有了这个表示,我们可以构建具有这些颜色的任何组合的集合:
BINARY DECIMAL COLOR
------ ------- -----
001 1 Red
010 2 Green
011 3 Red+Green
100 4 Blue
101 5 Blue+Red
110 6 Blue+Green
111 7 Blue+Green+Red
当位运算发挥作用时:我们可以使用它们在单个运算中构造集合和检查成员关系。
例如,我们可以用|
构造一组Red
和Blue
,如下所示:
Color purple = Red | Blue;
在幕后,所有这些都是将5
分配给purple
,因为4 | 1
就是5
。但是,由于您的程序将5
解释为两种颜色的集合,因此5
的含义与整数5
的含义不同,后者表示一个袋子中的东西数量。
您可以通过对集合应用&
来检查集合是否具有特定成员:
if (purple & Red) {
// returns true
}
if (purple & Green) {
// returns false
}
I/O库使用的标志以相同的方式工作。一些标志被组合以产生位掩码。它们的工作方式与单个标志相同,但不是让你找到成员身份,而是让你在一个比特操作中找到集合交集:
Color yellow = Blue | Green;
Color purple = Red | Blue;
Color common = yellow & purple; // common == Blue
如果我们采用GNU libstdc++实现,看看它们是如何实际实现的,我们会发现:
enum _Ios_Openmode
{
_S_app = 1L << 0,
_S_ate = 1L << 1,
_S_bin = 1L << 2,
_S_in = 1L << 3,
_S_out = 1L << 4,
_S_trunc = 1L << 5,
_S_ios_openmode_end = 1L << 16
};
然后这些值如下所示:
typedef _Ios_Openmode openmode;
static const openmode app = _S_app;
/// Open and seek to end immediately after opening.
static const openmode ate = _S_ate;
/// Perform input and output in binary mode (as opposed to text mode).
/// This is probably not what you think it is; see
/// http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt11ch27s02.html
static const openmode binary = _S_bin;
/// Open for input. Default for @c ifstream and fstream.
static const openmode in = _S_in;
/// Open for output. Default for @c ofstream and fstream.
static const openmode out = _S_out;
/// Open for input. Default for @c ofstream.
static const openmode trunc = _S_trunc;
由于这些值被选择为1 << n
,它们每个恰好是一个"位",这允许我们使用|
(或)以及其他类似的操作进行组合。
所以二进制文件中的app
是0000 0001
,bin
是0000 0100
,所以如果我们将app | bin
作为打开文件的模式,我们得到0000 0101
。实现fstream
的内部可以使用
if (mode & bin) ... do stuff for binary file ...
和
if (mode & app) ... do stuff for appending to the file ...
其他C++库实现可以为每个标志选择一组不同的位值,但将使用类似的系统。
"幕后",在计算机的内存中,每个信息最终都被编码为一组比特。您的CPU可以对这些基本信息执行基本的二进制代数运算(AND、OR、XOR、NOT)。
C++运算符CCD_ 29、CCD_ 30和CCD_。对于标志管理,明智的做法是使用无符号整数类型,如unsigned int
或unsigned char
。
概述:
- 诀窍是每个标志都对应一个固定的位。这通常是用2的幂常数(例如:1,2,4,8,二进制编码为000100100100和1000)来完成的
- 常数之所以命名,是因为它比使用乱丢垃圾更清晰(例如:
const unsigned FlagA=1, FlagB=2, FlagC=4;
) - 二进制AND
x & y
确保只有在x和y中都为1的比特保持为1。因此,这是用来通过"安定"重置标志,其中标志为0。因此x & FlagB
重置除标志B以外的所有标志 - 二进制OR
x | y
在x或y中为1的任何位变为1。所以它被用来设置标志。示例:x | FlagB
设置标志B - 二进制AND也是检查是否设置了标志的快速方法:当且仅当设置了标志B时,
(x & FlagB)
将为真
编辑:关于ifstream::open()
参数的具体问题:这是一个设计选择,方便使用。正如您所看到的,有6个标志会影响文件的处理方式(其中一些很少使用)。因此,不是每次都提供6个标志中的每一个,而是标准决定在开放模式中组合提供它们。可变数量的参数不是一种选择,因为被调用的函数必须知道您提供了多少个参数。
- 即使使用调试编译标志,表达式也是"optimized out"
- 在轮班操作后使用携带标志
- 每次使用带有LOCK_EX标志的LOCK_NB时,相同的程序/进程都会获取锁
- 如何使用 gnu gcc 标志 -mpc32、-mpc64 和 -mpc80?
- 使用 boost::p rogram_options 指定多个标志
- 如何告诉 gcc 显示您使用的优化标志列表
- 在setiosflags函数中使用十六进制标志
- 使用 std::atomic 标志和 std::condition_variable 在工作线程上等待
- cmake在构建过程中使用另一个工具检测标志
- 使用-L和-L标志与将库文件作为输入进行比较
- 如何使用带有"--gcov tool"标志的lcov
- 我必须在 c++ 中使用标志吗?
- 有关使用标志位设置内部错误标志的说明
- 重载运算符时可以使用标志吗?
- 为什么重载运算符不与 std::string 一起使用 msvc /MD 标志
- 使用 -O1 优化标志编译项目时共享库崩溃
- 是否可以使用 GCC 编译具有特定编译器标志的代码文件的一部分?
- 当自动编译对象文件时,如何使我的makefile使用我的cflags标志
- 如何使用 CMake 传递编译器标志以使用 GTest
- 为Qt项目创建一个标志或使用QLoggingCategory