2010-06-11 14 views
53

Tôi đang làm việc để triển khai giao thức memcache, tại một số điểm, sử dụng giá trị số nguyên 64 bit. Các giá trị này phải được lưu trữ trong "thứ tự byte mạng".Có chức năng htonl "chuẩn" nào cho các số nguyên 64 bit trong C++ không?

Tôi muốn có một số chức năng uint64_t htonll(uint64_t value) để thực hiện thay đổi, nhưng rất tiếc, nếu nó tồn tại, tôi không thể tìm thấy.

Vì vậy, tôi có 1 hoặc 2 câu hỏi:

  • di (Windows, Linux, AIX) chức năng tiêu chuẩn để làm việc này?
  • Nếu không có chức năng như vậy, bạn sẽ triển khai như thế nào?

Tôi đã lưu ý đến việc triển khai cơ bản nhưng tôi không biết cách kiểm tra tính cuối cùng trong thời gian biên dịch để làm cho mã di động. Vì vậy, sự giúp đỡ của bạn được hoan nghênh hơn ở đây;)

Cảm ơn bạn.


Đây là giải pháp cuối cùng tôi đã viết, nhờ giải pháp của 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

có thể trùng lặp của http://stackoverflow.com/questions/809902/64-bit-ntohl-in-c – INS

+0

@ereOn: Tôi cũng có câu hỏi tương tự [tại đây] (http://stackoverflow.com/ câu hỏi/19393539/how-to-swap-64-bit-số nguyên trong khi trích xuất-byte-từ-bytearray-in-c). Nếu có thể, bạn có thể xem và cho tôi biết tôi đang làm gì sai ở đây? – AKIWEB

+1

Thay vì bao gồm câu trả lời của bạn bên trong câu hỏi, bạn nên để câu trả lời của bạn với câu trả lời. Nó dễ đọc hơn. – mpromonet

Trả lời

15

Có thể bạn đang tìm kiếm bswap_64 Tôi nghĩ rằng nó được hỗ trợ khá nhiều ở mọi nơi nhưng tôi sẽ không gọi nó là tiêu chuẩn.

Bạn có thể dễ dàng kiểm tra độ tin cậy bằng cách tạo một giá trị int có giá trị là 1, đúc địa chỉ int của bạn dưới dạng char* và kiểm tra giá trị của byte đầu tiên.

Ví dụ:

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

Biết được điều này bạn cũng có thể thực hiện một chức năng đơn giản mà không được trao đổi.


Bạn cũng có thể sử dụng tăng cường chứa macro cuối cùng là nền tảng chéo di động.

+0

Cảm ơn;) Các macro 'boost' có vẻ thú vị. Bạn có liên kết? – ereOn

+1

Xem http://www.boost.org/doc/libs/1_37_0/boost/detail/endian.hpp –

+3

Về mặt kỹ thuật, chỉ cần trao đổi byte không phải lúc nào cũng đủ. Có những hệ thống trung cấp (mặc dù không có * hệ thống * hiện đại). Ngoài ra, 'bswap_64' chắc chắn là * KHÔNG * được hỗ trợ ở mọi nơi; chỉ cần nhìn vào danh sách dài các hệ thống bị thiếu 'bswap_64': https://www.gnu.org/software/gnulib/manual/html_node/bswap_005f64.html –

-3

EDIT: kết hợp hai (sử dụng mã của 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; 
} 

Cảnh báo: Mã chưa được kiểm tra! Vui lòng kiểm tra trước khi sử dụng.

+0

@Pavel Vẫn không hoạt động. 'htonl()' trả về một giá trị 32 bit mà bạn không thể ** gọi '<< 32LL' (bởi vì bạn không thể dịch chuyển 32 bit còn lại trên một giá trị 32 bit duy nhất). – ereOn

+0

Tôi nghĩ rằng chuyển bằng 32LL sẽ làm quảng bá bên trái, phải không? –

+0

@Pavel: không, kích thước bit của giá trị thay đổi không thay đổi bất cứ điều gì. gcc phát ra cảnh báo: "số lần dịch chuyển trái> = chiều rộng của loại". Và hàm của bạn nói rằng htonll (0x0102030405060708ULL) == 0xc070605. – bstpierre

4

Điều này dường như hoạt động trong C; tôi có làm gì sai không?

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

Để giảm chi phí của "nếu num == ..." Sử dụng tiền xử lý định nghĩa:

#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)) 

Bài kiểm tra (1 htonl == (1)) chỉ đơn giản là xác định (tại thời gian chạy đáng buồn) nếu kiến ​​trúc phần cứng requres byte trao đổi. Không có bất kỳ cách di động nào để xác định tại thời điểm biên dịch kiến ​​trúc là gì, vì vậy chúng tôi sử dụng "htonl", điều này có thể di động như trong tình huống này. Nếu yêu cầu hoán đổi byte, thì chúng ta trao đổi 32 bit tại một thời điểm bằng cách sử dụng htonl (nhớ để trao đổi hai từ 32 bit).

+1

Tôi chắc chắn câu trả lời này là tuyệt vời, nhưng bạn có thể vui lòng thêm một cái gì đó khác hơn là mã để giải thích những gì và tại sao? – AndyG

+0

Cảm ơn! Tôi đã chỉnh sửa câu trả lời của bạn với lời giải thích. – AndyG

+0

như đã đề cập @ereon bạn không thể sử dụng 32 bit thay đổi trên 'ntohl' hoặc' ntohl' vì chúng trả về 'uint32_t', do đó kích hoạt UB. – Aif

1

Bạn có thể thử với uint64_t htobe64(uint64_t host_64bits) & uint64_t be64toh(uint64_t big_endian_64bits) cho ngược lại.

+1

Vâng, không, tôi không thể vì đã hơn 6 năm kể từ khi tôi chạm vào codebase đó;) – ereOn