从 4 字节 char 数组到 int 的精度损失?

loss of precision from 4 byte char array to int?

我正在尝试从 /dev/random 中提取整数值的数据。下面的代码有效。我想了解的是为什么我必须对最终输出使用 size_t 类型以避免精度损失。查看代码中的注释。

我认为问题可能是 .read 方法添加了某种类型的填充,例如空终止字符,我尝试将长度设置为 3 以避免出现这种情况,但这似乎并不重要。我很高兴知道如何解决这个问题,但我想了解为什么我必须这样做。

size_t getSeed()
{
    std::ifstream rnd ("/dev/random", std::ios::binary);
    if( rnd.is_open() )
    {
        int len = sizeof(int);               // 4 bytes
        char* blk = new char [len];
        rnd.read ( blk, len );               // 8 bytes?
        rnd.close();
        size_t out = (size_t)*blk;           // loss of precision with int
        delete[] blk;
        return out;
    }
    else
    {
        return 0;
    }
}  

我不明白你为什么以二进制模式读取 4 char 然后将它们保存到 int,即 size_t。直接从流读取到 size_t out 会更容易:

 size_t out;
 rnd.read ( &out, sizeof(out) );

但是,如果这只是一个实验,我想向您推荐一些变体,将 4 个字符打包成一个 32 位整数。

第一个(C 风格)选项 union:

#include <cstdint>

union ConversionUnion
{
    int32_t dint;
    char dchar[4];
}; 

int32_t getSeed()
{
    std::ifstream rnds ("/dev/random", std::ios::binary);
    ConversionUnion conv;
    if( rnds.is_open() )
    {
        rnds.read (conv.dchar, sizeof(int32_t ));
        rnds.close();
        return conv.dint;
    }
    else
    {
        return 0;
    }
} 

如果您只想修复代码,请尝试更改行

size_t out = (size_t)*blk; 

到行(这也是 C 而不是 C++)

size_t out = *((size_t*)blk);

同时考虑用于 4 个数字(不是数组)的解决方案 - here。但是同样的方法可以用于数组:

    int32_t result = 0;
    for(int i = 0; i < 4; i++) // or
    // for(int i = 3; i > 0; i--)  // for reverse order of bytes if needed
    {
        result <<= 8;
        result |= blk[i];
    }