0

背景:这个问题是这个问题的后续。
给定的答案建议通过unsigned char *而不是char*成功访问数据。

主要问题:但是如果我们别无选择,我们该怎么办?(即,如果char*由函数原型强加)。


语境:

假设我们已将int二进制格式的数组写入文件。
它可能看起来像(没有错误检查):

const std::string bin_file("binary_file.bin");

const std::size_t len(10);
int test_data[len] {-4000, -3000, -2000, -1000, 0, 1000, 2000, 3000, 4000, 5000};

std::ofstream ofs(bin_file, std::ios::trunc | std::ios::binary);
for(std::size_t i = 0; i < len; ++i)
{
    ofs.write(reinterpret_cast<char*>(&test_data[i]), sizeof test_data[i]);
}
ofs.close();

现在我想打开文件,读取它,将之前写入的数据一一打印出来。

打开如下执行(不检查错误):

std::ifstream ifs(bin_file, std::ios::binary); // open in binary mode

// get the length
ifs.seekg(0, ifs.end);
std::size_t byte_size = static_cast<std::size_t>(ifs.tellg());
ifs.seekg(0, ifs.beg);

此时,byte_size == len*sizeof(int)


可能的解决方案:

我知道我可以通过以下方式做到这一点:

int val;
for(std::size_t i = 0; i < len; ++i)
{
    ifs.read(reinterpret_cast<char*>(&val), sizeof val);
    std::cout << val << '\n';
}

或通过:

int vals[len];
ifs.read(reinterpret_cast<char*>(vals), static_cast<std::streamsize>(byte_size));

for(std::size_t i = 0; i < len; ++i)
    std::cout << vals[i] << '\n';

这两种解决方案都可以正常工作,但它们都不是这个问题的目的。


问题描述:

我在这里考虑我想将完整的二进制文件内容放入 achar*并在之后处理它的情况。
我不能使用,unsigned char*因为std::ifstream::read()期待char*.

我试过了:

char * buff = new char[byte_size];
ifs.read(buff, static_cast<std::streamsize>(byte_size));

int val = 0;
for(std::size_t i = 0; i < len; ++i)
{
    // Get the value via std::memcpy works fine
    //std::memcpy(&val, &buff[i*sizeof val], sizeof val);

    // Get the value via bit-wise shifts fails (guess: signedness issues)
    for(std::size_t j = 0; j < sizeof val; ++j)
        val |= reinterpret_cast<unsigned char *>(buff)[i*sizeof val + j] << CHAR_BIT*j; // For little-endian

    std::cout << val << '\n';
}

delete[] buff;

ifs.close();

通过std::memcpy将 4 个字节复制到 中int,我得到了预期的结果(打印val的 s 与原始值相同)。

通过按位移位,即使使用reinterpret_cast<unsigned char*>缓冲区,我也会得到垃圾值,导致无法取回原始int值(打印val的 s 是“垃圾”值:与原始值不同)。

我的问题是:什么是能够从 a而不是whilestd::memcpy中取回正确的值,而我的按位移位是不可能的? 我怎么能在不使用(出于一般利益目的)的情况下解决它?我想不通。char*unsigned char*
std::memcpy

4

1 回答 1

0

好吧,这是一个非常愚蠢的错误,真让我感到羞耻。

实际上,我忘记在每次下一次迭代之前重置val为零......

该问题与按位移位无关,并且reinterpret_cast<unsigned char *>工作成功。

更正后的版本应该是:

char * buff = new char[byte_size];
ifs.read(buff, static_cast<std::streamsize>(byte_size));

int val = 0;
for(std::size_t i = 0; i < len; ++i)
{
    for(std::size_t j = 0; j < sizeof val; ++j)
        val |= reinterpret_cast<unsigned char *>(buff)[i*sizeof val + j] << CHAR_BIT*j; // For little-endian

    std::cout << val << '\n';
    val = 0; // Reset the val
}

delete[] buff;

ifs.close();

对于那些不喜欢施法的人,我们可以将其替换为掩码,如下所示:

char * buff = new char[byte_size];
ifs.read(buff, static_cast<std::streamsize>(byte_size));

int val = 0;
for(std::size_t i = 0; i < len; ++i)
{
    int mask = 0x000000FF;
    for(std::size_t j = 0; j < sizeof val; ++j)
    {
        val |= (buff[i*sizeof val + j] << CHAR_BIT*j) & mask; // For little-endian
        mask = mask << CHAR_BIT;
    }

    std::cout << val << '\n';
    val = 0; // Reset the val
}

delete[] buff;

ifs.close();

问题来自键盘和椅子之间的完美示例:)

于 2019-11-12T14:43:46.837 回答