《redis设计与实现》_第二章_两种字符串C和SDS、区别、获取字符串长度及缓冲区溢出

《redis设计与实现》-- 第二章知识内容

redis中涉及到的两种字符串

c语言传统字符串
即以空格结尾的字符数组,简称c字符串。

SDS(simple dynamic string)——简单动态字符串
SDS是redis的默认字符串表示。

redis也会用到c字符串,但是只会作为字符串字面量,用在一些不用修改的字符串上面。
eg:

redisLog(REDIS_WARING,"Redis is now ready to exit, bye bye ...");

这里,“ …”中的内容即是字符串字面量。当redis需要的不仅仅是字符串字面量时,就会使用SDS来表示字符串值。

redis中的键值对
eg:redis> SET msg "hello world" OK
在例子中键值对中的键说的就是 msg,它是一个字符串对象,其底层实现是一个保存着"msg"字符串的SDS。
同理,“hello world”即为值,也是字符串对象,底层是保存着“hello world”字符串的SDS。

当键值对中值有多个时,此时的值就是一个列表对象,而在列表对象中包含了多个字符串对象,其中每个字符串对象都由一个SDS来实现。
关于什么是字符串对象,什么是列表对象,现在不做分析。

SDS的主要用途
1.保存数据库中的字符串值
2.被用作缓冲区(buffer):AOF模块中的AOF缓冲区,客户端状态中的输入缓冲区。

SDS的定义
sds.h/sdshdr 结构表示一个SDS值:

struct sdshdr
{
	//记录buf数组中已经使用的字节数
	//即为SDS所保存字符串的长度
	int len;
	//记录buf数组中未使用字节的数量
	int free;
	//字节数组,保存字符串
	char buf[];
}

可以看到buf数组中已经插满了元素,所以free的值为0,len的值为5(即字符串buf的长度,5字节长的字符串)
free值为0,表示SDS没有未分配的空间
len值为5,表示SDS保存了一个五字节长度的字符串
buf是char类型数组,默认在字符串结尾添加’\0’表示结束。

c语言以空字符串结尾,保存空字符’\0’的1字节空间并不会被计算到字符串长度里面,它是被额外分配的1字节空间,是自动分配的。SDS遵循此规则。

遵循此规则的好处
可以直接重用一部分c字符串函数库中的函数。
eg:定义一个指针s指向sdshdr,sdshdr *s。此时调用c库中<stdio.h>/printf函数,即:

printf("%s",s->buf);

可以直接调用printf函数来打印输出,无需再为SDS编写打印函数。
下面展示一个SDS分配了五字节未使用空间的结构。
2-2
结构很容易理解。

SDS与C字符串的区别
C字符串
在这里插入图片描述
c字符串使用N+1的字符数组来表示长度为N的字符串,并在最后一个元素总是空字符’\0’。

SDS
在这里插入图片描述
SDS以复杂度O(1)来获取字符串长度
显然SDS不仅可以保存字符串,而且可以记录字符串长度,以及buf剩余的未使用空间长度。

而c字符串要想获取字符串长度,就需要从头到尾进行遍历,就复杂度上SDS为O(1)<C为O(n)

SDS的长度工作是SDS的API执行时,自动完成的。这样,SDS将获取字符串长度从O(n)降低到O(1),确保了获取字符串长度不会影响redis的性能。

SDS杜绝缓冲区溢出
C字符串容易造成缓冲区溢出(buffer overflow)。
<string.h>/strcat。该函数是将src中的字符串内容拼接到dest字符串的末尾:

char *strcat(char *dest,const char *src);

上文中讲到,C字符串并不会记录长度,所以strcat这个函数会假定用户在调用此函数时,用户以及为dest分配了足够的内存空间,但事实上,一旦为dest分配的空间不足以容纳src中的所有内容,就会产生缓冲区溢出。

例:现有两个字符串s1和s2如下图。
在这里插入图片描述
执行 strcat(s1,“Cluster”);
此时s1中的内容就会溢出到s2的位置上,而s2的内容会因此被间接地修改。如图所示
在这里插入图片描述
SDS的空间分配策略可以完全杜绝发生缓冲区溢出的可能性:
SDSAPI要对SDS进行修改时,API执行步骤。
1.检查SDS的空间大小是否满足修改所需的要求。
2.若不满足则API自动将SDS扩展至所需大小
3.执行API实际的修改操作
所以SDS不需手动修改空间大小,也无需担心缓冲区溢出问题。
以sdscat(s,“Cluster”);为例。(该函数是SDS的拼接函数对应strcat函数)
在这里插入图片描述
现在执行函数
在这里插入图片描述
可以看到,sdscat函数会先检查空间是否足够,在发现不足以拼接"Cluster"时,先拓展了空间,然后执行拼接操作。

拼接后有一个有趣的现象:此时空间多出了13字节的未使用的内存空间,这又与什么有关呢?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值