什么是以长度为前缀的string克服零终止string的问题?
什么是以长度为前缀的string克服零终止string的问题?
我正在阅读书写伟大的代码卷。 我想到了这个问题。
一个问题是,以零终止的string,你必须不断findstring的结尾。 这个效率低下的典型例子是连接成一个缓冲区:
char buf[1024] = "first"; strcat(buf, "second"); strcat(buf, "third"); strcat(buf, "fourth");
在每次调用strcat
,程序必须从string的开头开始,find终止符以知道从哪里开始追加。 这意味着函数花费越来越多的时间寻找随着string长度增加而追加的地方。
用一个长度为前缀的string,相当于strcat
函数将知道结束的立即位置,并且会在追加到长度后更新长度。
代表string的每种方式都有优点和缺点,它们是否会给你带来问题取决于你正在用string做什么,以及哪些操作需要高效。 上面描述的问题可以通过手动跟踪string末尾的跟踪来克服,因此通过更改代码可以避免性能成本。
一个问题是,你不能在零终止的string中存储空字符(值为零)。 这使得不可能存储一些字符编码以及encryption的数据。
带长度前缀的string不受此限制。
首先澄清一下:C ++string(即std::string
) 不需要直到C ++ 11结束为零 。 他们总是提供对零终止的Cstring的访问。
由于历史原因, C风格的string以0字符结尾。
你指的问题主要是安全问题:零结束的string需要有一个零终止符。 如果他们缺乏(无论什么原因),string的长度变得不可靠,他们可能会导致缓冲区溢出问题(恶意攻击者可以通过在不应该的地方写入任意数据来利用这些问题.DEP有助于缓解这些问题但在这里是关键的话题)。
Poul-Henning Kamp在“最昂贵的单字节错误”中总结得最好。
- 性能成本:在块中操作内存会更便宜,如果您总是需要查找空字符,则无法完成。 换句话说,如果你事先知道你有一个129个字符的string,那么在64,64和1个字节的部分而不是逐个字符的操作可能会更有效率。
-
安全:Marco A.已经很难打到这一步了。 超过和低于运行的string缓冲区仍然是黑客攻击的主要途径。
-
编译器开发成本:大的开销与优化编译器的空终止string有关,而使用地址和长度格式会更容易。
-
硬件开发成本:硬件开发成本对于与空终止string相关的string特定指令也很大。
可以使用带长度前缀的string实现更多的额外function:
-
可能有多种types的长度前缀,可以通过string指针/引用标识的第一个字节的一个或多个位来标识。 作为交换确定string长度的额外时间,可以使用例如短string的单字节前缀和更长string的更长前缀。 如果使用大量的1-3字节string,与使用固定的4字节前缀相比,这种string的总内存消耗可以节省50%以上; 这种格式也可以适应长度超过32位整数范围的string。
-
人们可以将长度可变的string存储在边界检查的缓冲区中,其长度前缀中只有一位或两位。 与其他位结合的数字N将指示三件事之一:
-
一个N字节的string
-
(可选)保存零长度string的N字节缓冲区
-
一个N字节的缓冲区,如果它的最后一个字节B小于248,则保存一个长度为NB-1的string; 如果248或更多,则前面的B-247字节将存储缓冲区大小和string长度之间的差异。 请注意,如果string的长度正好是N-1,则string后面跟着一个NUL字节,如果它小于string后面的字节将不被使用,并且可以设置为NUL。
使用这种方法,需要在使用之前初始化强缓冲区(以指示它们的长度),但是不再需要将string缓冲区的长度传递给要在那里存储数据的例程。
-
-
可以使用某些前缀值来表示各种特殊的东西。 例如,可能有一个前缀表示它没有后面跟着一个string,而是一个string数据指针和两个给出缓冲区大小和当前长度的整数。 如果对string进行操作的方法调用一个获取数据指针,缓冲区大小和长度的方法,那么可以通过这样的方法来廉价地传递一个string的一部分,只要string本身将超过方法调用。
-
有人可能会扩展上述function,以表明string数据是在
malloc
生成的区域,并可能需要resize; 此外,可以安全地有方法,有时会返回堆中分配的dynamic生成的string,有时会返回一个不可变的静态string,并让收件人执行“如果它不是静态的,则释放此string”。
我不知道是否有任何前缀string实现实现了所有这些奖金function,但是它们都可以在存储空间中花费很less的代价,相对较less的代码成本,以及比使用NUL-终止的string,其长度既不知道也不短。
什么是以长度为前缀的string克服零终止string的问题?
没有任何。
这只是眼睛的糖果。
带有长度前缀的string作为其结构的一部分具有关于string有多长的信息。 如果你想用零终止的string来做同样的事情,你可以使用一个辅助variables;
lpstring = "foobar"; // saves '6' somewhere "inside" lpstring ztstring = "foobar"; ztlength = 6; // saves '6' in a helper variable
许多C库函数都使用零终止string,并且不能使用'\0'
字节之后的任何内容。 这是函数本身的问题,而不是string结构。 如果你需要处理带有零的零终止string的函数,写你自己的。