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都需要以网络字节序的格式填写(参见我的另一篇博文:套接字地址结构),那么问题来了,我们要自己写函数要进行主机字节序和网络字节序的转换吗?
当然不需要,软件工程法则中的一条:我们需要理解原理,但实际工程中不要重复造*,普通常见问题肯定有前人已经做过了,找到他们的解决方案即可。
- 网络字节序制定大端字节序
- 在<netinet/in.h>中(也是定义套接字地址结构的文件)
#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, const void *src, size_t n);使用具体细节man查询,不予概述
在学习工作中总结的需要注意的几点:
- mem开头的函数面向的是字节,能用的情况尽量使用这类函数,效率普遍较高。一种很常用的情况,对数组的初始化赋值。
- 当源字节串与目标直接串重叠,memcpy的操作结果不可知(出现的概率极低,但有一次我挂过彩--调试好久才查到这个问题,不堪回首的过去啊),这时我们需要使用ANSI c的memmove函数
3.地址转换
4.读写函数
#include <unistd.h>
ssize_t read(int fd, void *buf, size_t count);
返回值:读到的字节数,若已经到达文件尾,返回0;若出错,返回-1
read函数非常非常重要,里面有许多应该注意的点,一定要完全弄清楚
- 参数中的fd指的什么?全称File Descriptor,文件描述符。百度百科对文件描述符的描述:文件描述符在形式上是一个非负整数。实际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适用于UNIX、Linux这样的操作系统。以后我会专门写一篇博文来详解文件描述符机制。
-
可能使实际读到的字节数少于要求读的字节数的情况:
- 读普通文件时,在读到要求字节数前已经到达了文件尾端(这种很常见)
- 当从终端读入时,通常一次最多读一行
- 当从网络中读时,网络中的缓冲机制可能造成返回值小于所要求的字节数
- 当从管道或FIFO读时,如若管道包含的字节小于所需要的量,read返回实际可用的字节数
- 当从某些面向记录的设备(如磁带)读时,一次最多只能读取一个记录
- 当一信号造成中断,而已经读了部分数据量时(此种情况以后讨论)
#include<unistd.h>
ssize_t write(int fd, const void *buf, size_t nbytes);
返回值:若成功,返回已 写的字节数;若出错,返回-1
此处联系一些我之前写的博客:应用进程写数据到一个tcp套接字中发生的事情,此处就是调用的write
readn,writen讲解参见我的另一篇博文:readn,writen函数