如果我们打开一个文件进行阅读,我们可以定义一个或多个状态标志,
例如: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)
答案 0 :(得分:3)
位标志的表示方式与表示所有积分值的方式完全相同。是什么让他们"旗帜"是您的计划对其价值观的解释。
位标志用于小型值集的紧凑表示。为每个值分配一个位索引。将该索引处的位设置为1
的所有整数都解释为包含相应成员的集合。
考虑一个小例子:让我们说我们需要代表一组三种颜色 - 红色,绿色和蓝色。我们为红色指定零,绿色和索引为1,蓝色指数为2。这对应于以下表示:
BINARY DECIMAL COLOR
------ ------- -----
001 1 Red
010 2 Green
100 4 Blue
请注意,每个标志是2的幂。这是二进制数的属性,其单个位设置为1
。以下是它在C ++中的外观:
enum Color {
Red = 1 << 0
, Green = 1 << 1
, Blue = 1 << 2
};
1 << n
是构建整数的标准方法,位置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
答案 1 :(得分:2)
如果我们采用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
作为打开文件的模式,我们会{ {1}}。然后0000 0101
的充实内部可以使用
fstream
和
if (mode & bin) ... do stuff for binary file ...
其他C ++库实现可以为每个标志选择一组不同的位值,但是将使用类似的系统。
答案 2 :(得分:1)
“在场景后面”,在计算机的存储器中,每个信息最终被编码为一组比特。您的CPU已连线以对此类基本信息执行基本binary algebra操作(AND,OR,XOR,NOT)。
C ++运算符|
&
和^
只能直接访问任何整数类型的CPU操作。对于标志管理,最好使用无符号整数类型,例如unsigned int
或unsigned char
。
快递概述:
const unsigned FlagA=1, FlagB=2, FlagC=4;
)x & y
确保只有x和y中为1的位保持为1.因此,这用于通过“anding”以标志为0的值重置标志。所以{{1}重置所有标志exept标志B x & FlagB
在x或y中为1的任何位变为1.因此它用于设置标志。示例:x | y
设置标志B。x | FlagB
才为真。 编辑:关于ifstream::open()
参数的具体问题:为方便起见,这是一个设计选择。正如您所看到的,有6个标志会影响文件的处理方式(其中一些很少使用)。因此,标准不是每次都提供6个标志中的每一个,而是决定您将它们组合在一个开放模式中。可变数量的参数不是替代方案,因为被调用函数必须知道您提供了多少个参数。