为什么C不使用特殊的转义字符串终止字符终止字符串?

时间:2009-07-19 22:48:50

标签: c string null escaping

在C中,字符串以null(\ 0)终止,当您想在字符串中放置null时会导致问题。为什么不使用特殊的转义字符,例如\ $或其他东西?

我完全清楚这个问题是多么愚蠢,但我很好奇。

8 个答案:

答案 0 :(得分:39)

以0结尾有许多性能细节,这在60年代后期非常相关。

CPU有0条测试条件跳转的指令。实际上,有些CPU甚至有指令将迭代/复制字节序列到0。

如果您使用转义字符,则有两个测试两个不同的字节来断言字符串的结尾。这不仅速度较慢,而且您无法一次迭代一个字节,因为您需要前瞻或能够回溯。

现在,其他语言(咳嗽,咳嗽,咳嗽)使用计数/值样式的字符串。对于他们来说,任何字符都是有效的,但它们总是保持一个字符串大小的计数器。优点很明显,但这种技术也有缺点。

首先,字符串大小受计数所需的字节数限制。一个字节为您提供255个字符,两个字节为您提供65535等。今天可能几乎无关紧要,但每次为每个字符串添加两个字节非常昂贵。

修改

我不认为这个问题是愚蠢的。在这些具有内存管理,令人难以置信的CPU能力和大量内存的高级语言的日子里,过去的这些决定似乎毫无意义。而且,事实上,他们现在可能毫无意义,所以对他们提出质疑是件好事。

答案 1 :(得分:13)

你需要一些实际字节值来终止字符串 - 你在代码中表示它的方式并不真正相关。

如果使用\$来终止字符串,它在内存中会有什么字节值?你如何在字符串中包含该字节值?

如果使用特殊字符终止字符串,无论你做什么,都会遇到这个问题。另一种方法是使用计数字符串,其中字符串的表示包括其长度(例如BSTR)。

答案 2 :(得分:2)

我猜是因为它检查起来更快,并且完全不可能在合理的字符串中出现。 另外,请记住C没有字符串的概念。 C中的字符串本身不是什么东西。它只是一个字符数组。它被称为字符串并被用作字符串的事实纯粹是偶然的和传统的。

答案 3 :(得分:1)

它会导致问题,但您可以嵌入\ 0 ...

const char* hello = "Hello\0World\0\0";

如果将其传递给标准库函数strlen,则会导致问题,但不会出现问题。

比任何字符串终止字符更好的解决方案可能是预先添加字符串的长度,如...

const char* hello = "\x0BHello World";

......这是其他一些语言的做法。

答案 4 :(得分:0)

如果标准库函数(如strlen或printf)可以(按选项)查找字符串结尾标记\ 777(作为\ 000的替代),则可以使用包含\ 0s的常量字符串:

const char* hello = "Hello\0World\0\0\777"; 
printf("%s\n", hello); 

顺便说一句,如果你想将\ 0发送到stdout(又名-print0),你可以使用:

putchar(0); 

答案 5 :(得分:0)

同样的历史原因。

C ++中std :: string的创建者认识到了这个缺点,因此std :: string可以包含null字符。 (但要小心constructing a std::string with a null character!)

如果你想要一个带有空字符的C字符串(或者说是一个准C字符串),你必须制作自己的结构。

typedef struct {
    size_t length;
    char[] data; //C99 introduced the flexible array member
} my_string;

或者您必须以其他方式跟踪字符串长度并将其传递给您编写的每个字符串函数。

答案 6 :(得分:0)

不刻意删除帖子,但这仍然与嵌入式SQL高度相关。

如果您在C中处理二进制数据,则应该在数据结构中创建二进制对象。如果你能负担得起,一串char就足够了。无论如何它可能不是一个字符串,是吗?

对于散列/摘要值,通常将它们“HEX”输出为{'0',..,'F'}的成员。 然后,在数据库操作期间,这些可以是“UNHEXED”。

对于文件操作,请考虑具有逻辑记录长度的二进制流。

如果您能保证编码,那么自己逃避它们是非常安全的。事实上,这可以在MYSQLDUMP(SQL)卸载中看到,其中二进制文件被正确转义为UTF-8,并且安装方案被“推送”以用于加载并且之后“弹出”。

我不主张使用dbms调用应该是一个库函数,但我已经看到它完成了。 (选择real_escape_string($ string))。

还有base64,这是另一种蠕虫病毒。 Google UUENCODE。

所以是的,如果你的角色是固定的宽度,mem *会起作用。

答案 7 :(得分:-1)

除了作为终结符之外,没有理由将nul字符作为字符串的一部分;它没有图形表示,因此您不会看到它,也不会充当控制字符。就文本而言,它是带外的值,因为您可以在不使用不同表示的情况下获得(例如,像0xFFFF这样的多字节值)。

稍微改一下迈克尔的问题,您如何期待处理“Hello \ 0World \ 0”?