Search code examples
c++binaryfilesostreamrvalue

Write a rvalue integer in a ostream as a binary value


I'm trying to output an integer as binary in a std::ostream.

The first thing I tried was:

int MyInt(){return 42;}
//...
std::ostream out; //not actually this but any ostream will do
out<<MyInt();

This of course converts the int to a character string which isn't what I want.

I also found a way to make it work:

int value=MyInt();
out.write(reinterpret_cast<const char*>(&value), sizeof(int));

This outputs what I want however I have to use a temporary to hold the value while using the function directly like this:

 out.write(reinterpret_cast<const char*>(&(MyInt())), sizeof(int));

Will fail to compile because I can't take the address of a rvalue (unless it's bound to a const reference).

This made me try that:

out.write(&(const char&)(MyInt()), sizeof(int));

However while it does preserve the smallest byte the other ones are garbage. The results are also probably implementation-defined as far as I know so not a recommended solution even if it were to work.

A union can solve the problem and is probably nicer than a temporary variable.

union IntConverter{
    int i;
    char c[sizeof(int)];
    IntConverter(int in) :i(in){}
};
out.write(IntConverter(MyInt()).c, sizeof(int));

However, I would like to avoid having to write more code if possible and I'm out of ideas so I am asking if there is a better solution to solve this problem.


Solution

  • To be able to easily output an int in binary, I would use a wrapper class with a friend operator <<. It could easily be templated to accept integral of different sizes. For example:

    template<typename T>
    class BinInt {
    private:
        T i;
    
    public:
        BinInt(T i): i(i) {}
        friend std::ostream& operator << (std::ostream& os, const BinInt& b) {
            os.write(reinterpret_cast<const char *>(&(b.i)), sizeof(T));
            return os;
        }
        T val() {
            return i;
        }
    };
    

    You can use it as simply as:

    BinInt<int> bi(0x41424344);
    BinInt<short> bs(0x4546);
    std::cout << "Val:" << bi.val() << " - repr:" << bi << std::endl;
    std::cout << "Val:" << bs.val() << " - repr:" << bs << std::endl;
    

    and on a 32 bits little endian it gives:

    Val:1094861636 - repr:DCBA
    Val:17734 - repr:FE