本文共 2086 字,大约阅读时间需要 6 分钟。
一个16位的整数,由2个字节组成。内存中存储这两个字节的两种办法:
小端字节序:将低序字节存储在起始位置
大端字节序:将高序字节存储在起始位置
总而言之,多个字节值的哪一端(高序字节或者低序字节)存储在该值的起始地址来判定大端还是小端
面试中经常考到的:
编写程序来判断主机字节序
程序如下:
#include思路很简单,看看就知道int main(int argc,char ** argv){ int a = 0x12345678; char *p = (char*)&a; if(0x12 == *p) printf("big-endian\n"); else if(0x78 == *p) printf("little-endian\n"); return 0;} 在网络编程中,套接字地址结构中的端口号和ip都需要以网络字节序的格式填写(参见我的另一篇博文:),那么问题来了,我们要自己写函数要进行主机字节序和网络字节序的转换吗?
当然不需要,软件工程法则中的一条:我们需要理解原理,但实际工程中不要重复造轮子,普通常见问题肯定有前人已经做过了,找到他们的解决方案即可。
- 网络字节序制定大端字节序
- 在<netinet/in.h>中(也是定义套接字地址结构的文件)
#includeuint32_t htonl(uint32_t hostlong); // 返回网络字节序uint16_t htons(uint16_t hostshort); // 返回网络字节序uint32_t ntohl(uint32_t netlong); // 返回主机字节序uint16_t ntohs(uint16_t netshort); // 返回主机字节序
字节操纵函数是非常有用的函数集,以个人经验来讲,在项目中经常用到。源自4.2BSD的b开头的字节操纵函数已经过时,不建议使用,故此出不列举。那么问题来了,别人会问你,你怎么知道这些函数已经淘汰? 还记得man吗 man bzero
现今我们最常用的还是ANSI 的c函数
#includevoid *memset(void *dest, int c, size_t len);void *memcpy(void *dest, const void *src, size_t nbytes);int memcmp(const void *ptr1, const void *ptr2, size_t nbytes);void *memmove(void *dest, const void *src, size_t n); 使用具体细节man查询,不予概述
在学习工作中总结的需要注意的几点:
- mem开头的函数面向的是字节,能用的情况尽量使用这类函数,效率普遍较高。一种很常用的情况,对数组的初始化赋值。
- 当源字节串与目标直接串重叠,memcpy的操作结果不可知(出现的概率极低,但有一次我挂过彩--调试好久才查到这个问题,不堪回首的过去啊),这时我们需要使用ANSI c的memmove函数
#include <unistd.h> ssize_t read(int fd, void *buf, size_t count);
返回值:读到的字节数,若已经到达文件尾,返回0;若出错,返回-1
read函数非常非常重要,里面有许多应该注意的点,一定要完全弄清楚
#include<unistd.h>
ssize_t write(int fd, const void *buf, size_t nbytes);
返回值:若成功,返回已 写的字节数;若出错,返回-1
此处联系一些我之前写的博客:此处就是调用的write
readn,writen讲解参见我的另一篇博文: