在阅读redis源码/src/endianconv.c时遇到了一些不理解的语句
#include <stdint.h> /* Toggle the 16 bit unsigned integer pointed by *p from little endian to * big endian */ void memrev16(void *p) { unsigned char *x = p, t; t = x[0]; x[0] = x[1]; x[1] = t; } /* Toggle the 32 bit unsigned integer pointed by *p from little endian to * big endian */ void memrev32(void *p) { unsigned char *x = p, t; t = x[0]; x[0] = x[3]; x[3] = t; t = x[1]; x[1] = x[2]; x[2] = t; } /* Toggle the 64 bit unsigned integer pointed by *p from little endian to * big endian */ void memrev64(void *p) { unsigned char *x = p, t; t = x[0]; x[0] = x[7]; x[7] = t; t = x[1]; x[1] = x[6]; x[6] = t; t = x[2]; x[2] = x[5]; x[5] = t; t = x[3]; x[3] = x[4]; x[4] = t; } uint16_t intrev16(uint16_t v) { memrev16(&v); return v; } uint32_t intrev32(uint32_t v) { memrev32(&v); return v; } uint64_t intrev64(uint64_t v) { memrev64(&v); return v; } #ifdef TESTMAIN #include <stdio.h> int main(void) { char buf[32]; sprintf(buf,"ciaoroma"); memrev16(buf); printf("%s\n", buf); sprintf(buf,"ciaoroma"); memrev32(buf); printf("%s\n", buf); sprintf(buf,"ciaoroma"); memrev64(buf); printf("%s\n", buf); return 0; } #endif
从代码可知方法是用来低位与高位交换,但为什么要交换?
这里就要了解相关的Big_Endian&Little_Endian的知识。
Big_Endian是指低地址存放最高有效字节(MSB),而Little_Endian则是低地址存放最低有效字节(LSB),不同的CPU采用不同的方式存储数据。因此考虑到兼容性的问题,必须先判断主机CPU的存储方式,再进行字节序的转换工作。
redis中/src/config.h
/* Byte ordering detection */ #include <sys/types.h> /* This will likely define BYTE_ORDER */ #ifndef BYTE_ORDER #if (BSD >= 199103) # include <machine/endian.h> #else #if defined(linux) || defined(__linux__) # include <endian.h> #else #define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ #define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ #define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp)*/ #if defined(__i386__) || defined(__x86_64__) || defined(__amd64__) || \ defined(vax) || defined(ns32000) || defined(sun386) || \ defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ defined(__alpha__) || defined(__alpha) #define BYTE_ORDER LITTLE_ENDIAN #endif #if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ defined(apollo) || defined(__convex__) || defined(_CRAY) || \ defined(__hppa) || defined(__hp9000) || \ defined(__hp9000s300) || defined(__hp9000s700) || \ defined (BIT_ZERO_ON_LEFT) || defined(m68k) || defined(__sparc) #define BYTE_ORDER BIG_ENDIAN #endif #endif /* linux */ #endif /* BSD */ #endif /* BYTE_ORDER */ /* Sometimes after including an OS-specific header that defines the * endianess we end with __BYTE_ORDER but not with BYTE_ORDER that is what * the Redis code uses. In this case let's define everything without the * underscores. */ #ifndef BYTE_ORDER #ifdef __BYTE_ORDER #if defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) #ifndef LITTLE_ENDIAN #define LITTLE_ENDIAN __LITTLE_ENDIAN #endif #ifndef BIG_ENDIAN #define BIG_ENDIAN __BIG_ENDIAN #endif #if (__BYTE_ORDER == __LITTLE_ENDIAN) #define BYTE_ORDER LITTLE_ENDIAN #else #define BYTE_ORDER BIG_ENDIAN #endif #endif #endif #endif #if !defined(BYTE_ORDER) || \ (BYTE_ORDER != BIG_ENDIAN && BYTE_ORDER != LITTLE_ENDIAN) /* you must determine what the correct bit order is for * your compiler - the next line is an intentional error * which will force your compiles to bomb until you fix * the above macros. */ #error "Undefined or invalid BYTE_ORDER" #endif
做了详细的兼容
【用函数判断系统是Big Endian还是Little Endian】 bool IsBig_Endian() //如果字节序为big-endian,返回true; //反之为 little-endian,返回false { unsigned short test = 0x1122; if(*( (unsigned char*) &test ) == 0x11) return TRUE; else return FALSE; }