blog

リア向け。

Fortranで出したバイナリデータをC++で読む方法

たぶん(自分を含めて)誰も使わない。


Fortran code (output作成例)

program main
    integer,parameter :: N=256
    integer :: a=1,b=2,i
    real(8) :: arr(N),val=3.14d0

    forall(i=1:N) arr(i)=1.*i

    open(20,file="test.bin",form="unformatted")
    write(20) a,arr,b,val
    close(20)
end program


C++ (要Boost, C++11)

#define BOOST_RESULT_OF_USE_DECLTYPE
#define BOOST_SPIRIT_USE_PHOENIX_V3
#include<iostream>
#include<iterator>
#include<fstream>
#include<string>
#include<cassert>
#include<boost/spirit/include/qi.hpp>
#include<boost/spirit/include/qi_repeat.hpp>
#include<boost/spirit/include/support_multi_pass.hpp>
#include<boost/fusion/include/vector.hpp>

namespace spirit = boost::spirit;
namespace qi     = boost::spirit::qi;
namespace fusion = boost::fusion;

int main() {
    const std::string filename = "test.bin";
    const int N=256;
    fusion::vector<int,
        int, std::vector<double>, int, double,
        int> store;
    fusion::at_c<2>(store).reserve(N);

    std::ifstream ifs(filename, std::ios::binary);
    using iterator_type   = std::istreambuf_iterator<char>;
    auto first = spirit::make_default_multi_pass(iterator_type(ifs)),
         last  = spirit::make_default_multi_pass(iterator_type());
    const auto ret
        = qi::parse(first,last,
                   qi::dword
                >> qi::dword >> qi::repeat(N)[qi::bin_double] >> qi::dword >> qi::bin_double
                >> qi::dword
                 , store);
    assert(ret && fusion::front(store)==fusion::back(store));

    for(auto v : fusion::at_c<2>(store)) {
        std::cout << v << ", ";     // 1, 2, 3, 4, 5, .. , 256
    }
    std::cout << fusion::at_c<4>(store) << std::endl;   // 3.14

    return 0;
}