簡體   English   中英

如何從二進制數據,跨平台(C / C ++)中讀取數字?

[英]How to read numeric from binary data, crossplatform (C/C++)?

我有原始的二進制數據塊(實際上是CBOR編碼的)。 要讀取數字,我使用常見的形式,例如:

template <typename T> // T can be uint64_t, double, uint32_t, etc...
auto read(const uint8_t *ptr) -> T {
    return *((T *)(ptr)); // all endianess-aware functions will be performed later
}

該解決方案可在x86/x86_64 PC和arm/arm64 iOS上運行。 但是,在具有clang編譯器且默認版本優化級別( -Os )的arm/armv7 Android上,我收到的SIGBUS的類型大於1個字節,且代碼為1 (未對齊讀取)。 我用另一個解決方案解決了這個問題:

template <typename T>
auto read(const uint8_t *ptr) -> T {
    union {
        uint8_t buf[sizeof(T)];
        T value;
    } u;
    memcpy(u.buf, ptr, sizeof(T));
    return u.value;
}

是否有任何獨立於平台的解決方案,不會影響性能?

警告 -這個問題的前提是機器的整數表示形式是little-endian。

唯一與平台無關的正確方法是使用memcpy。 您不需要工會。

不用擔心效率。 memcpy是一個魔術函數,編譯器將“做正確的事”。

為x86編譯時的示例:

#include <cstring>
#include <cstdint>

template <typename T>
auto read(const uint8_t *ptr) -> T {
  T result;
  std::memcpy(&result, ptr, sizeof(T));
    return result;
}

extern const uint8_t* get_bytes();
extern void emit(std::uint64_t);

int main()
{
  auto x = read<std::uint64_t>(get_bytes());
  emit(x);

}

產生匯編程序:

main:
        subq    $8, %rsp
        call    get_bytes()
        movq    (%rax), %rdi         ; note - memcpy utterly elided
        call    emit(unsigned long)
        xorl    %eax, %eax
        addq    $8, %rsp
        ret

注意:字節序

通過添加運行時字節序檢查,可以使該解決方案真正可移植。 實際上,編譯器將通過檢查來消除該檢查:

constexpr bool is_little_endian()
{
    short int number = 0x1;
    char *numPtr = (char*)&number;
    return (numPtr[0] == 1);
}


template <typename T>
auto read(const uint8_t *ptr) -> T {
  T result = 0;
  if (is_little_endian())
  {
    std::memcpy(&result, ptr, sizeof(result));
  }
  else
  {
    for (T i = 0 ; i < sizeof(T) ; ++i)
    {
      result += *ptr++ << 8*i;
    }
  }
  return result;
}

生成的機器代碼不變:

main:
        subq    $8, %rsp
        call    get_bytes()
        movq    (%rax), %rdi
        call    emit(unsigned long)
        xorl    %eax, %eax
        addq    $8, %rsp
        ret

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM