1.字节排序
一个16位的整数,由2个字节组成。内存中存储这两个字节的两种办法:
小端字节序:将低序字节存储在起始位置
大端字节序:将高序字节存储在起始位置
总而言之,多个字节值的哪一端(高序字节或者低序字节)存储在该值的起始地址来判定大端还是小端
面试中经常考到的:
编写程序来判断主机字节序
程序如下:
#include<stdio.h> 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都需要以网络字节序的格式填写(参见我的另一篇博文:套接字地址结构),那么问题来了,我们要自己写函数要进行主机字节序和网络字节序的转换吗?
当然不需要,软件工程法则中的一条:我们需要理解原理,但实际工程中不要重复造轮子,普通常见问题肯定有前人已经做过了,找到他们的解决方案即可。
#include <netinet/in.h> uint32_t htonl(uint32_t hostlong); // 返回网络字节序 uint16_t htons(uint16_t hostshort); // 返回网络字节序 uint32_t ntohl(uint32_t netlong); // 返回主机字节序 uint16_t ntohs(uint16_t netshort); // 返回主机字节序
2.字节操纵
字节操纵函数是非常有用的函数集,以个人经验来讲,在项目中经常用到。源自4.2BSD的b开头的字节操纵函数已经过时,不建议使用,故此出不列举。那么问题来了,别人会问你,你怎么知道这些函数已经淘汰? 还记得man吗 man bzero
现今我们最常用的还是ANSI 的c函数
#include <string.h> void *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,size_t n);使用具体细节man查询,不予概述
在学习工作中总结的需要注意的几点:
3.地址转换
4.读写函数
#include <unistd.h>ssize_t read(int fd,void *buf,size_t count);
返回值:读到的字节数,若已经到达文件尾,返回0;若出错,返回-1
read函数非常非常重要,里面有许多应该注意的点,一定要完全弄清楚
- 参数中的fd指的什么?全称File Descriptor,文件描述符。百度百科对文件描述符的描述:文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。以后我会专门写一篇博文来详解文件描述符机制。
- 可能使实际读到的字节数少于要求读的字节数的情况:
#include<unistd.h>
ssize_t write(int fd,const void *buf,size_t nbytes);
返回值:若成功,返回已 写的字节数;若出错,返回-1
此处联系一些我之前写的博客:应用进程写数据到一个tcp套接字中发生的事情,此处就是调用的write
readn,writen讲解参见我的另一篇博文:readn,writen函数