Q如何交换字节?
AV7 Unix 有一个swab函数,但它似乎被遗忘了。
显式字节交换代码的问题在于,您必须根据数据的字节序和所使用的机器的字节序来决定是否调用它。问题 20.9 显示了如何做到这一点,但这很麻烦。
一个更好的解决方案是定义函数,这些函数可以在数据的已知字节序和所使用机器的(未知)字节序之间进行转换,并安排这些函数在已经匹配所需字节序的机器上成为“无操作”(no-ops)。一组这样的函数,最初随着 BSD 网络代码引入,但现在已广泛使用,是:ntohs, htons, ntohl,而htonl。这些函数用于在“网络”和“主机”字节序之间进行转换,分别用于“短”(short)或“长”(long)整数,其中“网络”序始终是大端序(big-endian),“短”整数始终是 16 位,“长”整数始终是 32 位。(这当然不是 C 的定义,但它与 C 的定义兼容;参见问题 1.1。)所以,如果您知道要转换的数据是大端序,您就可以使用这些函数。(关键是您*总是*调用这些函数,使您的代码更加简洁。每个函数要么在需要时交换字节,要么什么都不做。交换与否的决定是在为特定机器实现这些函数时做出的,而不是在许多不同的调用程序中多次做出。)
如果您确实需要编写自己的字节交换代码,那么两种明显的方法是再次使用指针或联合(union),如问题 20.9 中所示。以下是一个使用指针的示例:
void byteswap(char *ptr, int nwords) { char *p = ptr; while(nwords-- > 0) { char tmp = *p; *p = *(p + 1); *(p + 1) = tmp; p += 2; } }
以下是一个使用联合的示例:
union word { short int word; char halves[2]; }; void byteswap(char *ptr, int nwords) { register union word *wp = (union word *)ptr; while(nwords-- > 0) { char tmp = wp->halves[0]; wp->halves[0] = wp->halves[1]; wp->halves[1] = tmp; wp++; } }
这些函数交换两字节数据;扩展到四字节或更多字节应该很明显。使用联合的代码是不完美的,因为它假定传入的指针是字对齐的(word-aligned)。也可以编写接受单独源指针和目标指针的函数,或者接受单个字并返回交换后的值的函数。
参考文献:PCS 第 11 章第 179 页