笨办法学C 练习36:更安全的字符串

练习36:更安全的字符串

原文:Exercise 36: Safer Strings

译者:飞龙

我已经在练习26中,构建devpkg的时候介绍了Better String库。这个练习让你从现在开始熟悉bstring库,并且明白C风格字符串为什么十分糟糕。之后你需要修改liblcthw的代码来使用bstring。

为什么C风格字符串十分糟糕

当人们谈论C的问题时,“字符串”的概念永远是首要缺陷之一。你已经用过它们,并且我也谈论过它们的种种缺陷,但是对为什么C字符串拥有缺陷,以及为什么一直是这样没有明确的解释。我会试着现在做出解释,部分原因是C风格字符串经过数十年的使用,有足够的证据表明它们是个非常糟糕的东西。

对于给定的任何C风格字符串,都不可能验证它是否有效。

  1. 以'\0'结尾的C字符串是有效的。

  2. 任何处理无效C字符串的循环都是无限的(或者造成缓冲区溢出)。

  3. C字符串没有确定的长度,所以检查它们的唯一方法就是遍历它来观察循环是否正确终止。

  4. 所以,不通过有限的循环就不可能验证C字符串。

这个逻辑非常简单。你不能编写一个循环来验证C字符串是否有效,因为无效的字符串导致循环永远不会停止。就是这样,唯一的解决方案就是包含大小。一旦你知道了大小,你可以避免无限循环问题。如果你观察练习27中我向你展示的两个函数:

译者注:检验C风格字符串是否有效等价于“停机问题”,这是一个非常著名的不可解问题。

void copy(char to[], char from[]){    int i = 0;    // while loop will not end if from isn't '\0' terminated    while((to[i] = from[i]) != '\0') {        ++i;    }}int safercopy(int from_len, char *from, int to_len, char *to){    int i = 0;    int max = from_len > to_len - 1 ? to_len - 1 : from_len;    // to_len must have at least 1 byte    if(from_len copy函数添加检查来确保from字符串有效。你该怎么做呢?你编写了一个循环来检查字符串是否已'\0'结尾。哦,等一下,如果字符串不以'\0'结尾,那它怎么让循环停下?不可能停下,所以无解。无论你怎么做,你都不能在不知道字符串长度的情况下检查C字符串的有效性,这里safercopy包含了程度。这个函数没有相同的问题,因为他的循环一定会中止,即使你传入了错误的大小,大小也是有限的。译者注:但是问题来了,对于一个C字符串,你怎么获取其大小?你需要在这个函数之前调用strlen,又是一个无限循环问题。于是,bstring库所做的事情就是创建一个结构体,它总是包含字符串长度。由于这个长度对于bstring来说总是可访问的,它上面的所有操作都会更安全。循环是有限的,内容也是有效的,并且这个主要的缺陷也不存在了。BString库也带有大量所需的字串操作,比如分割、格式化、搜索,并且大多数都会正确并安全地执行。bstring中也可能有缺陷,但是经过这么长时间,可能性已经很低了。glibc中也有缺陷,所以你让程序员怎么做才好呢?## 使用 bstrlib有很多改进后的字符串库,但是我最喜欢bstrlib,因为它只有一个程序集,并且具有大多数所需的字符串功能。你已经在使用它了,所以这个练习中你需要从Better String获取两个文件,bstrlib.c和bstrlib.h。下面是我在liblcthw项目目录里所做的事情:

$ mkdir bstrlib
$ cd bstrlib/
$ unzip ~/Downloads/bstrlib-05122010.zip
Archive: /Users/zedshaw/Downloads/bstrlib-05122010.zip
...
$ ls
bsafe.c bstraux.c bstrlib.h bstrwrap.h license.txt test.cpp
bsafe.h bstraux.h bstrlib.txt cpptest.cpp porting.txt testaux.c
bstest.c bstrlib.c bstrwrap.cpp gpl.txt security.txt
$ mv bstrlib.h bstrlib.c ../src/lcthw/
$ cd ../
$ rm -rf bstrlib

make the edits

$ vim src/lcthw/bstrlib.c
$ make clean all
...
$

在第14行你可以看到,我编辑了bstrlib.c文件,来将它移动到新的位置,并且修复OSX上的bug。下面是差异:

25c25

include

2759c2759

if defined(GNUC) && !defined(APPLE)

我把包含修改为,然后修复2759行ifdef的问题。## 学习使用该库这个练习很短,只是让你准备好剩余的练习,它们会用到这个库。接下来两个联系中,我会使用bstrlib.c来创建Hashmap`数据结构。你现在应该阅读头文件和实现,之后编写tests/bstr_tests.c来测试下列函数,来熟悉这个库:bfromcstr从C风格字符串中创建一个bstring。blk2bstr与上面相同,但是可以提供缓冲区长度。bstrcpy复制bstring。bassign将一个bstring赋值为另一个。bassigncstr将bsting的内容设置为C字符串的内容。bassignblk将bsting的内容设置为C字符串的内容,但是可以提供长度。bdestroy销毁bstring。bconcat在一个bstring末尾连接另一个。bstricmp比较两个bstring,返回值与strcmp相同。biseq检查两个bstring是否相等。binstr判断一个bstring是否被包含于另一个。bfindreplace在一个bstring中寻找另一个,并且将其替换为别的。bsplit将bstring分割为bstrList。bformat执行字符串格式化,十分便利。blength获取bstring的长度。bdata获取bstring的数据。bchar获得bstring中的字符。你的测试应该覆盖到所有这些操作,以及你从头文件中发现的更多有趣的东西。在valgrind下运行测试,确保内存使用正确。#c、lxthw#


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部