从C ++中的二进制文件读取不同字节序的整数

时间:2018-11-29 01:19:14

标签: c++ casting type-conversion binaryfiles endianness

我正在读ESRI Shapefile,但令我沮丧的是,它在不同的点使用了大尾数法和小尾数法(例如,参见第4页的表以及第5至8页的表)。

所以我用C ++创建了两个函数,每个endianness都有一个。

uint32_t readBig(ifstream& f) {
    uint32_t num;
    uint8_t buf[4];
    f.read((char*)buf,4);
    num = buf[3] | buf[2]<<8 | buf[1]<<16 | buf[0]<<24;
    return num;
}

uint32_t readLittle(ifstream& f) {
    uint32_t num;
    f.read(reinterpret_cast<char *>(&num),4);
    //f.read((char*)&num,4);
    return num;
}

但是我不确定这是最有效的方法。 可以改善此代码吗?请记住,单个shapefile可以运行数千次,甚至数百万次。因此,即使其中一个函数调用另一个函数似乎也比拥有两个单独的函数差。使用reinterpret_cast或显式类型转换(char *)之间在性能上有区别吗?我应该在两个函数中使用相同的符号吗?

2 个答案:

答案 0 :(得分:2)

  1. 在指针类型之间进行铸造不会影响性能-在 在这种情况下,使编译器满意只是一种技术性。
  2. 如果您确实要为每个32位分别调用read 值,字节交换操作所花费的时间可能是 在噪音中。为了提高速度,您可能应该拥有自己的 缓冲层,以便您的内部循环不起作用 电话。
  3. 如果交换可以编译成单个操作码(例如bswap),那很好,但是无论是否 可能或最快的选择是特定于处理器的。
  4. 如果您真的对最大化速度感兴趣,请考虑使用SIMD内部函数。

答案 1 :(得分:1)

在大多数情况下,编译器应生成一条bswap指令,这可能已足够。但是,如果您需要更快的速度,vpshufb是您的朋友...

#include <immintrin.h>
#include <cstdint>

// swap byte order in 16 x int16
inline void swap_16xi16(uint16_t input[16])
{
  constexpr uint8_t mask_data[] = {
    1, 0, 
    3, 2,
    5, 4,
    7, 6,
    9, 8, 
    11, 10,
    13, 12,
    15, 14,
    1, 0, 
    3, 2,
    5, 4, 
    7, 6,
    9, 8, 
    11, 10,
    13, 12,
    15, 14
  };
  const __m256i swapped = _mm256_shuffle_epi8(
    _mm256_loadu_si256((const __m256i*)input), 
    _mm256_loadu_si256((const __m256i*)mask_data)
  );
  _mm256_storeu_si256((__m256i*)input, swapped);
}

// swap byte order in 8 x int32
inline void swap_8xi32(uint32_t input[8])
{
  constexpr uint8_t mask_data[] = {
    3, 2, 1, 0,
    7, 6, 5, 4,
    11, 10, 9, 8,
    15, 14, 13, 12,
    3, 2, 1, 0,
    7, 6, 5, 4,
    11, 10, 9, 8,
    15, 14, 13, 12
  };
  const __m256i swapped = _mm256_shuffle_epi8(
    _mm256_loadu_si256((const __m256i*)input), 
    _mm256_loadu_si256((const __m256i*)mask_data)
  );
  _mm256_storeu_si256((__m256i*)input, swapped);
}

// swap byte order in 4 x int64
inline void swap_4xi64(uint64_t input[4])
{
  constexpr uint8_t mask_data[] = {
    7, 6, 5, 4, 3, 2, 1, 0,
    15, 14, 13, 12, 11, 10, 9, 8,
    7, 6, 5, 4, 3, 2, 1, 0,
    15, 14, 13, 12, 11, 10, 9, 8
  };
  const __m256i swapped = _mm256_shuffle_epi8(
    _mm256_loadu_si256((const __m256i*)input), 
    _mm256_loadu_si256((const __m256i*)mask_data)
  );
  _mm256_storeu_si256((__m256i*)input, swapped);
}

inline void swap_16xi16(int16_t input[16])
  { swap_16xi16((uint16_t*)input); }
inline void swap_8xi32(int32_t input[8])
  { swap_8xi32((uint32_t*)input); }
inline void swap_4xi64(int64_t input[4])
  { swap_4xi64((uint64_t*)input); }
inline void swap_8f(float input[8])
  { swap_8xi32((uint32_t*)input); }
inline void swap_4d(double input[4])
  { swap_4xi64((uint64_t*)input); }