Search code examples
c++fstream

How are state flags represented and how bitwise OR is used to work with bit flags?


If we open a file for reading, we may define one or more state flags, for example: ios::out as well as ios::out | iso::app

I read about the bitwise OR, and how it "merges" the two bit sets,

for example: 1010 | 0111 = 1111

now that being said, I do not understand how it works "behind the scenes" when we use a method like ifstream.open(filename, stateflagA | stateflagB | stateflagC) and so on.

Can someone elaborate more on the inner workings of these state flags and their memory representation?

EDIT: To give more emphasis on what i am trying to understand (if it helps), I would assume that the open method could receive one or more state flags as separate arguments in the signature, and not delimited by a bitwise OR, so i want to understand how the bitwise OR works on these state flags to produce a different final state when combining several flags, and as a result allows me to use only one argument for a state flag or a set of state flags. ie:

ifstream.open(filename, stateflagA | stateflagB | stateflagC)

and NOT

ifstream.open(filename, stateflagA , stateflagB , stateflagC)

Solution

  • If we take the GNU libstdc++ implementation and look at how these are actually implemented, we find:

    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 
    };
    

    These values are then used as this:

    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;
    

    Since the values are chosen as 1 << n, they are exactly one "bit" each, which allows us to combine then using | (or) - as well as other similar operations.

    So app in binary is 0000 0001 and bin is 0000 0100, so if we do app | bin as a mode for opening the file, we get 0000 0101. The internals of the impplementation of fstream can then use

     if (mode & bin) ... do stuff for binary file ... 
    

    and

     if (mode & app) ... do stuff for appending to the file ...
    

    Other C++ library implementations may choose a different set of bit values for each flag, but will use a similar system.