【问题标题】:Read char from file on platform where bytes > 8 bits从字节> 8位的平台上的文件中读取字符
【发布时间】:2016-04-08 19:30:40
【问题描述】:

如果我有一个包含以下数据的二进制文件(写在 1 字节 == 8 位的平台上):0x01, 0x10, 0x20, 0x40, 0xff

following program 是否可以移植到platform where 1 byte != 8 bits?

#include <iterator>
#include <fstream>

int main()
{
    std::fstream file("binaryfile");
    std::istreambuf_iterator<char> iter{file}, end;
    for (; iter != end; ++iter) {
        char c{*iter};
    }
}

换句话说;如果读平台一个字节有16位,会读2个字节吗?

【问题讨论】:

  • @NathanOliver - 在这个时代的机器上,一个字节不是 8 位是真的吗?
  • 有各种嵌入式系统没有一个字节未定义为八位字节。
  • @NathanOliver 那是因为 POSIX 要求一个字节等于 8 位。
  • 原始二进制流格式无论如何都不可移植,您需要反序列化来解决这个问题。
  • @MuertoExcobito 一些 DSP 芯片使用 16 位“字节”。在这些环境中,sizeof(char) 按照标准应该返回 1,但它会是一个 16 位的“char”。

标签: c++


【解决方案1】:

大多数程序可能不可移植

阅读 cmets here,我认为答案是该程序不完全符合 C++ 标准的可移植性。没有程序是。 edit:至少没有程序与网络通信、读取或写入磁盘或期望其他平台回答或更新数据。

C++ 支持平台的硬件,而不是 Java。例如,fgetc 和 fputc 保留往返值,但仅在同一平台上。网络消息之所以有效,是因为每个人都假设一个字节有 8 位。

如果有问题,最好断言平台有 8 位到一个字节:static_assert(CHAR_BIT==8, "Platform must have 8 bits to a byte.");

即使没有断言,也会有其他警钟。一个没有 8 位到一个字节,但仍然通过网络或文件与其他平台通信的平台将比稍后失败,并且将代码移植到它将需要额外的工作来读取和写入假设的 8 位数据 事实上的标准。这看起来很像字节顺序问题,但这里的区别是一方非常明显地赢了。

但它们可以制成便携式

编辑:上面的陈述可能并不总是成立。通过适当的努力,可以使程序变得可移植。以下来自 Mooing Duck 的改编演示了该程序和迭代器如何考虑如何处理不同位数的行为。它显示了具有更多位的系统如何从具有更少位的系统中读取文件。这可以扩展为双向工作:

#include <iterator>
#include <climits>
#include <iostream>

template<class base_iterator, size_t source_bits>
class bititerator : public std::iterator<std::input_iterator_tag, unsigned char> {
    mutable base_iterator base;
    mutable unsigned char bufferhi;
    mutable unsigned char bufferlo;
    mutable unsigned char bitc;
public:
    bititerator(const base_iterator& b) : base(b), bufferhi(0), bufferlo(0), bitc(0) {}
    bititerator& operator=(const bititerator&b) {base = b.base; bufferlo=b.bufferlo; bufferhi=b.bufferhi; bitc=b.bitc; return *this;}
    friend void swap(bititerator&lhs, bititerator&rhs) {std::swap(lhs.base, rhs.base); std::swap(lhs.bufferlo, rhs.bufferlo); std::swap(lhs.bufferhi, rhs.bufferhi); std::swap(lhs.bit, rhs.bitc);}
    bititerator operator++(int) {bititerator t(*this); ++*this; return t;}
    unsigned char* operator->() const {operator*(); return &bufferlo;}
    friend bool operator==(const bititerator&lhs, const bititerator&rhs) {return lhs.base==rhs.base && lhs.bitc==rhs.bitc;}
    friend bool operator!=(const bititerator&lhs, const bititerator&rhs) {return !(lhs==rhs);}
    unsigned char operator*() const {
        static_assert(source_bits<CHAR_BIT, "bititerator only works on systems with more bits than the target");
        //make sure at least source_bits bits are in the buffers
        if (bitc < source_bits) {
            bufferhi = static_cast<unsigned char>(*base);
            ++base;
            size_t shift = source_bits-bitc;
            bufferlo |= ((bufferhi<<shift)&0xFF);
            bufferhi >>= shift;
            bitc += CHAR_BIT;
        }
        return bufferlo;

    }
    bititerator& operator++() {
        operator*();
        //shift the buffers down source_bits bits
        bufferlo >>= source_bits;
        bufferlo |= ((bufferhi<<(CHAR_BIT-source_bits))&0xFF);;
        bufferhi >>= source_bits;
        bitc -= source_bits;
        return *this;
    }
};

template<class base_iterator>
bititerator<base_iterator,6> from6bit(base_iterator it) {return bititerator<base_iterator,6>(it);}
bititerator<std::istreambuf_iterator<char>,6> from6bitStart(std::istream& str) {return bititerator<std::istreambuf_iterator<char>,6>{std::istreambuf_iterator<char>{str}};}
bititerator<std::istreambuf_iterator<char>,6> from6bitEnd(std::istream& str) {return bititerator<std::istreambuf_iterator<char>,6>{std::istreambuf_iterator<char>{}};}

#include <fstream>
int main()
{
    std::fstream file("binaryfile");
    auto end = from6bitEnd(file);
    for (auto iter = from6bitStart(file); iter != end; ++iter)
        std::cout << *iter;
}

【讨论】:

  • “没有程序”,这是错误的。没错,我们用于现代文件和网络的基于 8 位标准的序列化会很困难,但这远非不可能。
  • @MooingDuck 这是证明我错了的机会。根据 C++ 标准,您将如何更新上述代码以完全可移植?
  • 这仅基于更少的位而不是更多位从源中读取,但可以灵活处理这两个问题:coliru.stacked-crooked.com/a/b569bbd878e68d6d 我很忙,因此未经测试。
  • @MooingDuck 哇。我站得更正。可以编写程序(甚至库),使其在每个字节的位数方面完全可移植。
  • 是的。不漂亮,不简单,而且肯定不快,但可以做到。
猜你喜欢
  • 1970-01-01
  • 2011-10-23
  • 2015-07-26
  • 1970-01-01
  • 2017-09-06
  • 2021-06-24
  • 1970-01-01
相关资源
最近更新 更多