1. sds vs c字符串
在 C 语言中,字符串可以用一个 \0
结尾的 char
数组来表示。
比如说, hello world
在 C 语言中就可以表示为 "hello world\0"
。
这种简单的字符串表示,在大多数情况下都能满足要求,但是,它并不能高效地支持长度计算和追加(append)这两种操作:
每次计算字符串长度(strlen(s))的复杂度为 O(N)。
对字符串进行 N 次追加,必定需要对字符串进行 N 次内存重分配(realloc)。
而redis除了要处理c语言字符串之外,还需要处理redis的服务器协议等等。所以,redis实现的sds(简单动态字符串),是二进制安全的。
数据结构的定义如下:
typedef char *sds;
struct sdshdr {
int len;// buf 已占用长度
int free;// buf 剩余可用长度
char buf[];// 实际保存字符串数据的地方
};
从上面的数据结构定义,可以看出,redis的sds和c语言的区别就是,sds是通过buf以及len来判断字符串内容的,而不是通过"\0"
来判断。
2. 二进制安全
判断字符串"1234\0123"
的长度,看下面代码:
//c语言
str="1234\0123";
strlen(str)=4
//redis
127.0.0.1:6379> set str 1234\0123
OK
127.0.0.1:6379> strlen str
(integer) 9
所以,简单来说,二进制安全就是,字符串不是根据某种特殊的标志来解析的,无论输入是什么,总能保证输出是处理的原始输入而不是根据某种特殊格式来处理。
比如这边redis通过strlen来表示字符串长度,不会因为中间插入了"\0"
就返回错误结果。
再举个非二进制安全的例子:
main(){
char ab[] = "Hello";
char ac[] = "Hello\0Hello";
strcmp(ab,ac);
//返回0,由于是非二进制安全,程序结果判断为相等
}