2

I was using the boost::multiprecision::uint128_t type in order to perform bitwise operations on a 128 bit value. However I am having trouble writing the 128 bit value out to a binary file. Specifically with the need to pad out the value with zeros.

As an example if the uint128_t value was 0x123456 then looking at the file in the hex editor I would want the sequence:

56 34 12 00 00 00 00 00 00 00 00 00 00 00 00 00

#include <boost/multiprecision/cpp_int.hpp>
#include <fstream>

boost::multiprecision::uint128_t temp = 0x123456;
std::ofstream ofile("test.bin", std::ios::binary);
ofile.write((char*)&temp, 16);
ofile.close();

Instead the binary file ends up with a value:

56 34 12 00 CC CC CC CC CC CC CC CC CC CC CC

I can see the the boost backend for the uint128_t template appears to store the 128 bits as four 32 bit values. And has a "limb" value which indicates how many 32 bit values are in use. When the 32 bit values are not in use they are filled with 0xCCCCCCCC. So the ofstream.write is walking through the array of characters and writing out the 0xC's.

Is there something I am missing in the boost library to help write this out correctly, or will I need to convert the uint128_t value into some another data type?

Andrew T.
  • 4,701
  • 8
  • 43
  • 62
Tim
  • 21
  • 3
  • 2
    the `(char*)` reinterpret_cast is ***evil*** and (obviously) doesn't work. See related answers on how to serialize using boost serialization: http://stackoverflow.com/a/28705686/85371 – sehe May 07 '15 at 01:22

1 Answers1

0

I dived into it, you can write a utility to write the contiguous limbs as POD objects:

Live On Coliru

#include <boost/multiprecision/cpp_int.hpp>
#include <fstream>

template <typename BigInt, typename Backend = typename BigInt::backend_type>
void write_binary(std::ostream& os, BigInt const& number) {
    static_assert(boost::is_pod<typename Backend::local_limb_type>::value, "not allowed");

    os.write(
            reinterpret_cast<char const*>(number.backend().limbs()), 
            number.backend().size()*sizeof(typename Backend::local_limb_type)
        );
}

int main()
{
    using uint128_t = boost::multiprecision::uint128_t;

    std::ofstream ofs("binary.dat", std::ios::binary);
    write_binary(ofs, uint128_t(42));
}

Hexdump:

0000000: 2a00 0000 0000 0000 0000 0000 0000 0000  *...............

I'm afraid this isn't portable (it may depend on the availability of compiler intrinsics for 128 bit numbers). At least it's type safe.

sehe
  • 374,641
  • 47
  • 450
  • 633
  • does it have boost::serialization support? – Sergei Krivonos May 13 '18 at 20:37
  • @Sergei oh, hah. That comment slipped through the cracks. Let me fix that up: https://www.boost.org/doc/libs/1_67_0/libs/multiprecision/doc/html/boost_multiprecision/tut/serial.html – sehe May 14 '18 at 23:00
  • @Sergei See also https://stackoverflow.com/a/28705686/85371, and the linked posts. Also tangentially related: https://stackoverflow.com/a/30111778/85371 – sehe May 14 '18 at 23:02
  • So how to convert uint8 data[] = {56 34 12 00 00 00 00 00 00 00 00 00 00 00 00 00} to a uint128_t? What I mean is, how to construct a uint128_t by a byte array? – alpha May 22 '18 at 09:56
  • @alpha that's a different question. If you can't find info on that or get stuck implementing it, you might post a question – sehe May 22 '18 at 11:35