1、Endian Order
什么是大小端字节序(Endian Order)?以四字节十六进制整型数0x12345678为例,按照书写习惯,从左到右,高位在前,低位在后,我们称0x12为最高有效字节,0x78为最低有效字节,在存储这个数字时,需要四字节的地址空间,比如说从0x00到0x03,地址空间是从低地址0x00到高地址0x03的一段连续地址,那么,低地址存储最高有效字节的形式为大端(Big Endian),反之,高地址存储最高有效字节的形式为小端(Little Endian),也就是说,大端字节序时,地址0x00存储数字0x12,0x01存储0x34,0x02存储0x56,0x03存储0x78,反之,小端字节序时,地址0x00存储数字0x78,0x01存储0x56,0x02存储0x34,0x03存储0x12,在实际使用中,大端字节序符合我们的书写习惯。另外,对于一个字节来说,其中的八个比特位也有类似的大小端比特序,常见的最高有效位MSB(Most Significant Bit)和最低有效位LSB(Least Significant Bit)就是从这里来的。由于数据传输是逐字节的,最小单位为字节,所以我们需要关心的是大小端字节序,网络字节序为大端字节序,大小端比特序可以忽略。
2、qbswap
对于给定的处理器来说,其大小端字节序是已知的,Qt在头文件qendian.h提供了若干对大小端进行处理的接口。首先是字节逆序函数qbswap_helper,因为在头文件中定义,所以必须指定为inline,以及模板函数qbswap,其中的转换结果dest不要求字节对齐,实现方式如下:
1 inline void qbswap_helper(const void *src, void *dest, int size) 2 { 3 for (int i = 0; i < size ; ++i) 4 static_cast<uchar *>(dest)[i] = static_cast<const uchar *>(src)[size - 1 - i]; 5 } 6 7 template <typename T> inline void qbswap(const T src, void *dest) 8 { 9 qbswap_helper(&src, dest, sizeof(T)); 10 }
3、考虑字节对齐
考虑到类型安全和字节对齐安全,提供了qToUnaligned
和qFromUnaligned
两个函数,以及六个模板特化函数qbswap
,如下:
1 template <typename T> Q_ALWAYS_INLINE void qToUnaligned(const T src, void *dest) 2 { 3 const size_t size = sizeof(T); 4 #if QT_HAS_BUILTIN(__builtin_memcpy) 5 __builtin_memcpy 6 #else 7 memcpy 8 #endif 9 (dest, &src, size); 10 } 11 12 template <typename T> Q_ALWAYS_INLINE T qFromUnaligned(const void *src) 13 { 14 T dest; 15 const size_t size = sizeof(T); 16 #if QT_HAS_BUILTIN(__builtin_memcpy) 17 __builtin_memcpy 18 #else 19 memcpy 20 #endif 21 (&dest, src, size); 22 return dest; 23 } 24 25 #if (defined(Q_CC_GNU) && Q_CC_GNU >= 403) || QT_HAS_BUILTIN(__builtin_bswap32) 26 template <> inline void qbswap<quint64>(quint64 source, void *dest) 27 { 28 qToUnaligned<quint64>(__builtin_bswap64(source), dest); 29 } 30 template <> inline void qbswap<quint32>(quint32 source, void *dest) 31 { 32 qToUnaligned<quint32>(__builtin_bswap32(source), dest); 33 } 34 #else 35 #endif // GCC & Clang intrinsics 36 37 #if (defined(Q_CC_GNU) && Q_CC_GNU >= 408) || QT_HAS_BUILTIN(__builtin_bswap16) 38 template <> inline void qbswap<quint16>(quint16 source, void *dest) 39 { 40 qToUnaligned<quint16>(__builtin_bswap16(source), dest); 41 } 42 #else 43 #endif // GCC & Clang intrinsics 44 45 // signed specializations 46 template <> inline void qbswap<qint64>(qint64 source, void *dest) 47 { 48 qbswap<quint64>(quint64(source), dest); 49 } 50 51 template <> inline void qbswap<qint32>(qint32 source, void *dest) 52 { 53 qbswap<quint32>(quint32(source), dest); 54 } 55 56 template <> inline void qbswap<qint16>(qint16 source, void *dest) 57 { 58 qbswap<quint16>(quint16(source), dest); 59 }
4、不考虑字节对齐
如果不考虑字节对齐问题,使用另一个版本的重载函数qbswap更方便,同样有六个特化模板,如下:
1 template <typename T> T qbswap(T source); 2 3 #if (defined(Q_CC_GNU) && Q_CC_GNU >= 403) || QT_HAS_BUILTIN(__builtin_bswap32) 4 template <> inline quint64 qbswap<quint64>(quint64 source) 5 { 6 return __builtin_bswap64(source); 7 } 8 template <> inline quint32 qbswap<quint32>(quint32 source) 9 { 10 return __builtin_bswap32(source); 11 } 12 #else 13 template <> inline quint64 qbswap<quint64>(quint64 source) 14 { 15 return 0 16 | ((source & Q_UINT64_C(0x00000000000000ff)) << 56) 17 | ((source & Q_UINT64_C(0x000000000000ff00)) << 40) 18 | ((source & Q_UINT64_C(0x0000000000ff0000)) << 24) 19 | ((source & Q_UINT64_C(0x00000000ff000000)) << 8) 20 | ((source & Q_UINT64_C(0x000000ff00000000)) >> 8) 21 | ((source & Q_UINT64_C(0x0000ff0000000000)) >> 24) 22 | ((source & Q_UINT64_C(0x00ff000000000000)) >> 40) 23 | ((source & Q_UINT64_C(0xff00000000000000)) >> 56); 24 } 25 26 template <> inline quint32 qbswap<quint32>(quint32 source) 27 { 28 return 0 29 | ((source & 0x000000ff) << 24) 30 | ((source & 0x0000ff00) << 8) 31 | ((source & 0x00ff0000) >> 8) 32 | ((source & 0xff000000) >> 24); 33 } 34 #endif // GCC & Clang intrinsics 35 36 #if (defined(Q_CC_GNU) && Q_CC_GNU >= 408) || QT_HAS_BUILTIN(__builtin_bswap16) 37 template <> inline quint16 qbswap<quint16>(quint16 source) 38 { 39 return __builtin_bswap16(source); 40 } 41 #else 42 template <> inline quint16 qbswap<quint16>(quint16 source) 43 { 44 return quint16( 0 45 | ((source & 0x00ff) << 8) 46 | ((source & 0xff00) >> 8) ); 47 } 48 #endif // GCC & Clang intrinsics 49 50 51 // signed specializations 52 template <> inline qint64 qbswap<qint64>(qint64 source) 53 { 54 return qbswap<quint64>(quint64(source)); 55 } 56 57 template <> inline qint32 qbswap<qint32>(qint32 source) 58 { 59 return qbswap<quint32>(quint32(source)); 60 } 61 62 template <> inline qint16 qbswap<qint16>(qint16 source) 63 { 64 return qbswap<quint16>(quint16(source)); 65 } 66 }
5、8 Bits
对于8个二进制位的类型来说,是不需要考虑大小端的,如下:
1 template <> inline quint8 qbswap<quint8>(quint8 source) 2 { 3 return source; 4 } 5 6 template <> inline qint8 qbswap<qint8>(qint8 source) 7 { 8 return source; 9 }
6、大小端转换
大小端转换涉及如下六个函数:
1 #if Q_BYTE_ORDER == Q_BIG_ENDIAN 2 3 template <typename T> inline T qToBigEndian(T source) 4 { return source; } 5 template <typename T> inline T qFromBigEndian(T source) 6 { return source; } 7 template <typename T> inline T qToLittleEndian(T source) 8 { return qbswap<T>(source); } 9 template <typename T> inline T qFromLittleEndian(T source) 10 { return qbswap<T>(source); } 11 template <typename T> inline void qToBigEndian(T src, void *dest) 12 { qToUnaligned<T>(src, dest); } 13 template <typename T> inline void qToLittleEndian(T src, void *dest) 14 { qbswap<T>(src, dest); } 15 #else // Q_LITTLE_ENDIAN 16 17 template <typename T> inline T qToBigEndian(T source) 18 { return qbswap<T>(source); } 19 template <typename T> inline T qFromBigEndian(T source) 20 { return qbswap<T>(source); } 21 template <typename T> inline T qToLittleEndian(T source) 22 { return source; } 23 template <typename T> inline T qFromLittleEndian(T source) 24 { return source; } 25 template <typename T> inline void qToBigEndian(T src, void *dest) 26 { qbswap<T>(src, dest); } 27 template <typename T> inline void qToLittleEndian(T src, void *dest) 28 { qToUnaligned<T>(src, dest); } 29 30 #endif // Q_BYTE_ORDER == Q_BIG_ENDIAN
如果不考虑字节对齐,还有下面几个特化模板。
1 template <typename T> inline T qFromLittleEndian(const void *src) 2 { 3 return qFromLittleEndian(qFromUnaligned<T>(src)); 4 } 5 6 template <> inline quint8 qFromLittleEndian<quint8>(const void *src) 7 { return static_cast<const quint8 *>(src)[0]; } 8 template <> inline qint8 qFromLittleEndian<qint8>(const void *src) 9 { return static_cast<const qint8 *>(src)[0]; } 10 11 template <class T> inline T qFromBigEndian(const void *src) 12 { 13 return qFromBigEndian(qFromUnaligned<T>(src)); 14 } 15 16 template <> inline quint8 qFromBigEndian<quint8>(const void *src) 17 { return static_cast<const quint8 *>(src)[0]; } 18 template <> inline qint8 qFromBigEndian<qint8>(const void *src) 19 { return static_cast<const qint8 *>(src)[0]; }
标签:Qt,dest,void,source,template,大小,inline,qbswap,字节 From: https://www.cnblogs.com/ybqjymy/p/18069841