POSIX rozetkasi orqali 64 bitli o'zgaruvchan portativ usul

Maxsus tarmoq protokolini loyihalashni rejalashtirmoqdamiz va uint64_t o'zgaruvchisiga (fayl uzunligini baytda ifodalash) ko'chma va socket POSIX-mos .

Afsuski, qo'lda , kenglik 64 bilan tamsayı turlarini bildiradi. kafolatlanmagan mavjud emas:

Agar dastur ushbu talablarga javob beradigan kenglik 64 bilan tamsayı turlarini taqdim qilsa, quyidagi turlar kerak: int64_t uint64_t

Bundan tashqari, htonl bilan mos POSIX mos emas. , htons , ntohl , ntohs (diqqat qiling: bswap_64 emas, balki POSIX-mos).

Soket orqali 64 bitli o'zgaruvchini yuborishning eng yaxshi usuli qanday?

1
qo'shib qo'ydi muallif chux, manba
qo'shib qo'ydi muallif chux, manba
Baytning tartibini belgilang va byte-wise bilan yuboring. Agar qabul qilgich qiymatdan foydalanishni xohlasa, qabul qiluvchining hujjatlashtirilgan bayt-tartibi amal qilishi kerak. Agar qabul qiluvchi 64-bit integers uchun o'rnatilgan qo'llab-quvvatlanmagan tizimda bo'lsa, uni ishlatishi mumkin bo'lgan kutubxonalar mavjud. Muxtasar qilib aytganda: nima qilayotganingizni yaxshi hujjatlashtiring va boshqa tomon siz bilan muvofiqligi haqida tashvishlansin.
qo'shib qo'ydi muallif Some programmer dude, manba
Baytning tartibini belgilang va byte-wise bilan yuboring. Agar qabul qilgich qiymatdan foydalanishni xohlasa, qabul qiluvchining hujjatlashtirilgan bayt-tartibi amal qilishi kerak. Agar qabul qiluvchi 64-bit integers uchun o'rnatilgan qo'llab-quvvatlanmagan tizimda bo'lsa, uni ishlatishi mumkin bo'lgan kutubxonalar mavjud. Muxtasar qilib aytganda: nima qilayotganingizni yaxshi hujjatlashtiring va boshqa tomon siz bilan muvofiqligi haqida tashvishlansin.
qo'shib qo'ydi muallif Some programmer dude, manba
Savol, albatta, soket haqida emas, balki, ketma-ket va serileştirici 64 bit tamsayıları portatif bir tarzda ikkilanmasdan. Buni rozetkaga jo'natish, uni faylga saqlash yoki boshqa narsalarni saqlash uchun bajarilganligi muhim emas.
qo'shib qo'ydi muallif Steffen Ullrich, manba
Savol, albatta, soket haqida emas, balki, ketma-ket va serileştirici 64 bit tamsayıları portatif bir tarzda ikkilanmasdan. Buni rozetkaga jo'natish, uni faylga saqlash yoki boshqa narsalarni saqlash uchun bajarilganligi muhim emas.
qo'shib qo'ydi muallif Steffen Ullrich, manba
Menimcha, 64-bit integerlarni qo'llab-quvvatlamaydigan tizimlar uchun kutubxonadan foydalanish juda ko'p. Men "C" da protokolni amalga oshirishni yozyapman, u juda past darajali va men istayman bu vaziyatni aqlli ravishda bitwise operatsiyalari va (ehtimol) makrolar yordamida boshqaring.
qo'shib qo'ydi muallif patryk.beza, manba
Menimcha, 64-bit integerlarni qo'llab-quvvatlamaydigan tizimlar uchun kutubxonadan foydalanish juda ko'p. Men "C" da protokolni amalga oshirishni yozyapman, u juda past darajali va men istayman bu vaziyatni aqlli ravishda bitwise operatsiyalari va (ehtimol) makrolar yordamida boshqaring.
qo'shib qo'ydi muallif patryk.beza, manba
@SteffenUllrich Men sizning ikkinchi linkni o'zimning birinchi savolimga qo'shib qo'ying. Birinchi havola savolimga javob bermaydi. Savolda socket konteksti mavjud, chunki men ushbu vaziyatni uy bilan bog'liq dasturlarda ko'rib chiqish uchun eng yaxshi amaliyotga javob berishning osonroq bo'lishiga umid qilgan edim. BTW: tegishli savol .
qo'shib qo'ydi muallif patryk.beza, manba
@SteffenUllrich Men sizning ikkinchi linkni o'zimning birinchi savolimga qo'shib qo'ying. Birinchi havola savolimga javob bermaydi. Savolda socket konteksti mavjud, chunki men ushbu vaziyatni uy bilan bog'liq dasturlarda ko'rib chiqish uchun eng yaxshi amaliyotga javob berishning osonroq bo'lishiga umid qilgan edim. BTW: tegishli savol .
qo'shib qo'ydi muallif patryk.beza, manba

6 javoblar

Siz faqat htonl() ilovasini ikki marotaba qo'llashingiz mumkin, albatta:

const uint64_t x = ...
const uint32_t upper_be = htonl(x >> 32);
const uint32_t lower_be = htonl((uint32_t) x);

Bu sizga 64 bitlik x o'zgarmaydiganining yuqori va quyi 32-bitlik qismlarining katta endian versiyasini o'z ichiga olgan ikkita 32-bitli parametrlarga ega bo'ladi.

Agar siz qattiq POSIX bo'lsangiz, u mavjud emasligi uchun kafolat bermagani uchun uint64_t dan foydalana olmaysiz. Keyin siz shunday bir narsa qilishingiz mumkin:

typedef struct {
 uint32_t upper;
 uint32_t lower;
} my_uint64;

Va to'g'ridan-to'g'ri to'g'ridan to'g'ri htonl() .

2
qo'shib qo'ydi

Siz faqat htonl() ilovasini ikki marotaba qo'llashingiz mumkin, albatta:

const uint64_t x = ...
const uint32_t upper_be = htonl(x >> 32);
const uint32_t lower_be = htonl((uint32_t) x);

Bu sizga 64 bitlik x o'zgarmaydiganining yuqori va quyi 32-bitlik qismlarining katta endian versiyasini o'z ichiga olgan ikkita 32-bitli parametrlarga ega bo'ladi.

Agar siz qattiq POSIX bo'lsangiz, u mavjud emasligi uchun kafolat bermagani uchun uint64_t dan foydalana olmaysiz. Keyin siz shunday bir narsa qilishingiz mumkin:

typedef struct {
 uint32_t upper;
 uint32_t lower;
} my_uint64;

Va to'g'ridan-to'g'ri to'g'ridan to'g'ri htonl() .

2
qo'shib qo'ydi

C99 yoki undan yuqori bo'lgan POSIX platformasini nazarda tutadigan bo'lsak {u,} int64_t mavjud emas, lekin {u,} int_ {eng kam, tez} 64_t mavjud.

Bundan tashqari, POSIX uchun {u,} int {8,16 , 32} _t .

Shunday qilib, nima qilishingiz mumkin:

#include 

//host-to-network (native endian to big endian)
void hton64(unsigned char *B, uint_least64_t X)
{

    B[0]=X>>56&0xFF;
    B[1]=X>>48&0xFF;
    B[2]=X>>40&0xFF;
    B[3]=X>>32&0xFF;
    B[4]=X>>24&0xFF;
    B[5]=X>>16&0xFF;
    B[6]=X>>8&0xFF;
    B[7]=X>>0&0xFF;
}

//network-to-host (big endian to native endian)
uint_least64_t ntoh64(unsigned char const *B)
{
    return (uint_least64_t)B[0]<<56|
           (uint_least64_t)B[1]<<48|
           (uint_least64_t)B[2]<<40|
           (uint_least64_t)B[3]<<32|
           (uint_least64_t)B[4]<<24|
           (uint_least64_t)B[5]<<16|
           (uint_least64_t)B[6]<<8|
           (uint_least64_t)B[7]<<0;
}

Agar mashinada uint64_t bo'lsa, uint64_t bilan bir xil bo'ladi (kod C tomonidan qo'yiladigan talablarga muvofiq).

Agar shunday bo'lmasa, u holda uint_least64_t ikkita qo'shimcha bo'lmasligi mumkin yoki u ko'proq qiymatli bitlarga ega bo'lishi mumkin (bunday me'morchiligi mavjudmi yoki yo'qmi, menda yo'q), lekin bundan qat'iy nazar yuqorida ko'rsatilgan qoidalar yoki (agar u mavjud bo'lsa) 64 ta past buyurtmaning bitini (tamponga yoki buferdan) aniq oling.

(Yaxshiyamki, bu yechim umumiy backend kabi yaxshi bo'lishi mumkin, lekin agar siz bir oz ko'proq optimal bo'lishni istasangiz, siz birinchi navbatda endiannessingizni aniqlab olishga harakat qilasiz va u katta endian platforma bo'lsa, hech narsa qilmang, agar u bir oz endian va Agar siz bswap_64 bilan byteswap.h ni topsangiz, unda bitta buyruqni kompilyatsiya qilish ehtimoli borligi sababli uni qo'llashingiz kerak bo'ladi. Agar barchasi muvaffaqiyatsiz bo'lsa, yuqoridagi kabi foydalaning.)

1
qo'shib qo'ydi

C99 yoki undan yuqori bo'lgan POSIX platformasini nazarda tutadigan bo'lsak {u,} int64_t mavjud emas, lekin {u,} int_ {eng kam, tez} 64_t mavjud.

Bundan tashqari, POSIX uchun {u,} int {8,16 , 32} _t .

Shunday qilib, nima qilishingiz mumkin:

#include 

//host-to-network (native endian to big endian)
void hton64(unsigned char *B, uint_least64_t X)
{

    B[0]=X>>56&0xFF;
    B[1]=X>>48&0xFF;
    B[2]=X>>40&0xFF;
    B[3]=X>>32&0xFF;
    B[4]=X>>24&0xFF;
    B[5]=X>>16&0xFF;
    B[6]=X>>8&0xFF;
    B[7]=X>>0&0xFF;
}

//network-to-host (big endian to native endian)
uint_least64_t ntoh64(unsigned char const *B)
{
    return (uint_least64_t)B[0]<<56|
           (uint_least64_t)B[1]<<48|
           (uint_least64_t)B[2]<<40|
           (uint_least64_t)B[3]<<32|
           (uint_least64_t)B[4]<<24|
           (uint_least64_t)B[5]<<16|
           (uint_least64_t)B[6]<<8|
           (uint_least64_t)B[7]<<0;
}

Agar mashinada uint64_t bo'lsa, uint64_t bilan bir xil bo'ladi (kod C tomonidan qo'yiladigan talablarga muvofiq).

Agar shunday bo'lmasa, u holda uint_least64_t ikkita qo'shimcha bo'lmasligi mumkin yoki u ko'proq qiymatli bitlarga ega bo'lishi mumkin (bunday me'morchiligi mavjudmi yoki yo'qmi, menda yo'q), lekin bundan qat'iy nazar yuqorida ko'rsatilgan qoidalar yoki (agar u mavjud bo'lsa) 64 ta past buyurtmaning bitini (tamponga yoki buferdan) aniq oling.

(Yaxshiyamki, bu yechim umumiy backend kabi yaxshi bo'lishi mumkin, lekin agar siz bir oz ko'proq optimal bo'lishni istasangiz, siz birinchi navbatda endiannessingizni aniqlab olishga harakat qilasiz va u katta endian platforma bo'lsa, hech narsa qilmang, agar u bir oz endian va Agar siz bswap_64 bilan byteswap.h ni topsangiz, unda bitta buyruqni kompilyatsiya qilish ehtimoli borligi sababli uni qo'llashingiz kerak bo'ladi. Agar barchasi muvaffaqiyatsiz bo'lsa, yuqoridagi kabi foydalaning.)

1
qo'shib qo'ydi

Mening shaxsiy sevimli makroim ... bu mening ishimga o'xshaydi va byte buyurtmasini qanday boshqarishni tanlashdan oldin mahalliy byte buyurtmalarini tekshiradi:

// clang-format off
#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
#   if defined(__has_include)
#     if __has_include()
#      include 
#     elif __has_include()
#      include 
#     endif
#   endif
#   if !defined(__LITTLE_ENDIAN__) &&                                             \
                (defined(__BIG_ENDIAN__) || __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#      define __BIG_ENDIAN__
#      define bswap64(i)   (i)//do nothing
#   else
#      define __LITTLE_ENDIAN__
#      define bswap64(i) ((((i)&0xFFULL) << 56) | (((i)&0xFF00ULL) << 40) |     \
          (((i)&0xFF0000ULL) << 24) | (((i)&0xFF000000ULL) << 8) |              \
          (((i)&0xFF00000000ULL) >> 8) | (((i)&0xFF0000000000ULL) >> 24) |      \
          (((i)&0xFF000000000000ULL) >> 40) |                                   \
          (((i)&0xFF00000000000000ULL) >> 56)) 
#   endif
#endif
1
qo'shib qo'ydi

Mening shaxsiy sevimli makroim ... bu mening ishimga o'xshaydi va byte buyurtmasini qanday boshqarishni tanlashdan oldin mahalliy byte buyurtmalarini tekshiradi:

// clang-format off
#if !defined(__BIG_ENDIAN__) && !defined(__LITTLE_ENDIAN__)
#   if defined(__has_include)
#     if __has_include()
#      include 
#     elif __has_include()
#      include 
#     endif
#   endif
#   if !defined(__LITTLE_ENDIAN__) &&                                             \
                (defined(__BIG_ENDIAN__) || __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#      define __BIG_ENDIAN__
#      define bswap64(i)   (i)//do nothing
#   else
#      define __LITTLE_ENDIAN__
#      define bswap64(i) ((((i)&0xFFULL) << 56) | (((i)&0xFF00ULL) << 40) |     \
          (((i)&0xFF0000ULL) << 24) | (((i)&0xFF000000ULL) << 8) |              \
          (((i)&0xFF00000000ULL) >> 8) | (((i)&0xFF0000000000ULL) >> 24) |      \
          (((i)&0xFF000000000000ULL) >> 40) |                                   \
          (((i)&0xFF00000000000000ULL) >> 56)) 
#   endif
#endif
1
qo'shib qo'ydi