2010-06-11 59 views
53

我正在研究memcache協議的實現,它在某些點上使用64位整數值。這些值必須以「網絡字節順序」存儲。C++中是否有64位整數的「標準」htonl函數?

我希望有一些uint64_t htonll(uint64_t value)功能來做改變,但不幸的是,如果它存在,我找不到它。

所以,我有1個或2個問題:

  • 是否有任何便攜式(在Windows,Linux,AIX)標準函數來做到這一點?
  • 如果沒有這樣的功能,你會如何實現它?

我記得一個基本的實現,但我不知道如何在編譯時檢查字節序以使代碼可移植。所以你的幫助是比這裏更受歡迎的;)

謝謝。


這是我寫的最終解決方案,這要感謝Brian的解決方案。

uint64_t htonll(uint64_t value) 
{ 
    // The answer is 42 
    static const int num = 42; 

    // Check the endianness 
    if (*reinterpret_cast<const char*>(&num) == num) 
    { 
     const uint32_t high_part = htonl(static_cast<uint32_t>(value >> 32)); 
     const uint32_t low_part = htonl(static_cast<uint32_t>(value & 0xFFFFFFFFLL)); 

     return (static_cast<uint64_t>(low_part) << 32) | high_part; 
    } else 
    { 
     return value; 
    } 
} 
+2

這個可能的重複http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c – INS 2010-06-11 13:05:47

+0

@ereOn:我也有類似的問題[這裏](http://stackoverflow.com/問題/ 19393539 /如何對交換-64位整數,而解壓字節從 - ByteArray的功能於c)中。如果可能的話,你可以看看,讓我知道我在這裏做什麼錯誤? – AKIWEB 2013-10-16 05:10:42

+1

你不應該在問題中包含你的答案,而應該讓你的答案與答案一致。它更具可讀性。 – mpromonet 2015-08-29 15:24:55

回答

15

您可能正在尋找bswap_64我認爲這是支持幾乎無處不在,但我不會把它的標準。

您可以通過創建一個值爲1的int,將您的int地址轉換爲char*並檢查第一個字節的值來輕鬆檢查字節順序。

例如:

int num = 42; 
if(*(char *)&num == 42) 
{ 
    //Little Endian 
} 
else 
{ 
    //Big Endian 
} 

知道了這一點,你也可以做一個簡單的函數,它的交換。


你也可以總是使用boost,它包含可移植跨平臺的endian宏。

+0

謝謝;)'boost'宏看起來很有趣。你有鏈接嗎? – ereOn 2010-06-11 12:41:08

+1

查看http://www.boost.org/doc/libs/1_37_0/boost/detail/endian.hpp – 2010-06-11 13:18:08

+3

從技術上講,只是字節交換並不總是足夠的。有些系統是中端的(儘管沒有*現代*系統)。另外,'bswap_64'絕對不*支持到處;只需看看'bswap_64'缺少的系統列表:https://www.gnu.org/software/gnulib/manual/html_node/bswap_005f64.html – 2015-02-11 13:20:39

-3

編輯:兩者結合(使用Brian的代碼):

uint64_t htonll(uint64_t value) 
{ 
    int num = 42; 
    if(*(char *)&num == 42) 
      return (htonl(value & 0xFFFFFFFF) << 32LL) | htonl(value >> 32); 
    else 
      return value; 
} 

警告:未經測試的代碼!使用前請先測試。

+0

@Pavel仍然不起作用。 'htonl()'返回一個32位的值,你不能**調用'<< 32LL'(因爲你不能在32位值上移位32位)。 – ereOn 2010-06-11 13:08:30

+0

我認爲通過32LL轉移會左側晉級,不是嗎? – 2010-06-11 15:03:15

+0

@Pavel:不,移位值的位大小不會改變任何東西。 gcc發出警告:「左移count> =類型的寬度」。你的函數說htonll(0x0102030405060708ULL)== 0xc070605。 – bstpierre 2010-08-02 19:52:45

4

這似乎工作在C;我做錯了什麼?

uint64_t htonll(uint64_t value) { 
    int num = 42; 
    if (*(char *)&num == 42) { 
     uint32_t high_part = htonl((uint32_t)(value >> 32)); 
     uint32_t low_part = htonl((uint32_t)(value & 0xFFFFFFFFLL)); 
     return (((uint64_t)low_part) << 32) | high_part; 
    } else { 
     return value; 
    } 
} 
1

爲了減少 「如果num == ...」 使用預處理器的開銷定義:

#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 
#else 
#endif 
12
#define htonll(x) ((1==htonl(1)) ? (x) : ((uint64_t)htonl((x) & 0xFFFFFFFF) << 32) | htonl((x) >> 32)) 
#define ntohll(x) ((1==ntohl(1)) ? (x) : ((uint64_t)ntohl((x) & 0xFFFFFFFF) << 32) | ntohl((x) >> 32)) 

試驗(1個== htonl(1) )只是簡單地確定(在運行時),硬件架構是否需要字節交換。在編譯時沒有任何可移植的方法來確定架構是什麼,所以我們訴諸使用「htonl」,它在這種情況下具有便攜性。如果需要字節交換,那麼我們一次使用htonl交換32位(還記得交換兩個32位字)。

+1

我相信這個答案很好,但是你可以添加一些代碼來解釋什麼和爲什麼嗎? – AndyG 2015-02-18 20:40:44

+0

謝謝!我已經用解釋編輯了你的答案。 – AndyG 2015-02-19 14:55:24

+0

正如@ereon所提到的,你不能在'ntohl'或'ntohl'上使用32位移位,因爲它們返回'uint32_t',因此觸發UB。 – Aif 2017-05-17 11:08:29

1

您可以嘗試使用uint64_t htobe64(uint64_t host_64bits) & uint64_t be64toh(uint64_t big_endian_64bits)反之亦然。

+1

嗯,不,我不能,因爲我已經超過6年了,因爲我觸及了這個代碼庫;) – ereOn 2017-10-25 16:55:11

相關問題