如何表示状态标志以及如何使用按位OR来处理位标志?

时间:2015-03-28 10:03:08

标签: c++ fstream

如果我们打开一个文件进行阅读,我们可以定义一个或多个状态标志, 例如: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)

3 个答案:

答案 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 | 15。但是,由于您的程序将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,因此它们各自只有一个“位”,这使我们可以使用|(或)以及其他类似操作进行组合。

二进制文件中app0000 0001bin0000 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 intunsigned char

快递概述:

  • 技巧是每个标志对应一个固定位。这通常以2常数的幂来完成(例如:1,2,4,8,二进制编码为0001,0010,0100和1000)。
  • 常量被命名,因为它比使用litterals更清晰(例如:const unsigned FlagA=1, FlagB=2, FlagC=4;
  • 二进制AND x & y确保只有x和y中为1的位保持为1.因此,这用于通过“anding”以标志为0的值重置标志。所以{{1}重置所有标志exept标志B
  • 二进制OR x & FlagB在x或y中为1的任何位变为1.因此它用于设置标志。示例:x | y设置标志B。
  • 二进制AND也是检查标志是否设置的快速方法:当且仅当标志B已设置时,x | FlagB才为真。

编辑:关于ifstream::open()参数的具体问题:为方便起见,这是一个设计选择。正如您所看到的,有6个标志会影响文件的处理方式(其中一些很少使用)。因此,标准不是每次都提供6个标志中的每一个,而是决定您将它们组合在一个开放模式中。可变数量的参数不是替代方案,因为被调用函数必须知道您提供了多少个参数。