为什么字符串字面值可能不是字符串?

3
我在C标准中遇到了关于字符串字面量的部分问题,特别是其中的第二部分:“在第7个转换阶段中,对由一个或多个字符串字面量得出的每个多字节字符序列追加一个值为零的字节或代码。80)”
“80) 一个字符串字面量可能并不是一个字符串(参见7.1.1),因为可以通过使用\0转义序列将空字符嵌入其中。”
我不理解这个解释中的“因为可以通过使用\0转义序列将空字符嵌入其中”这部分。
关于“字符串”的定义,在引用的第7.1.1节中如下所述:
“字符串是以第一个空字符结尾(包括第一个空字符)的一系列连续字符。”
我想过焦点可能在“可以”上,即字符串字面量不必包含/嵌入空字符,而字符串必须包含。但我又问自己:如果一个字符串字面量没有以空字符结尾,如何将其作为字符串使用(这对于字符串操作函数是必需的,以确定字符串的结束位置)?
我完全不知道该怎么做。
注意:我知道字符串字面量存储在只读内存中不能被修改,而“string”是指以NUL结尾的字符序列,可以或不可以被修改。
因此,我的问题不是:“什么是字符串和字符串字面量的区别?”
我的问题是:
为什么/如何字符串字面量可能不是一个字符串?
根据我目前的疑虑,下面两个问题是否正确?
字符串字面量可以省略NUL字节吗?
我想自己问这个问题,但在发布之前,我得到了线索。我的困惑是由于引用中某些词汇的不恰当使用而产生的。
但我决定不删除问题的草稿,因为它可能对未来的读者有用,并提供一个 Q&A。
随意评论和提示。
相关内容:

2
我会说这是文档中的一个错误 -- 当有 char *p = "foo\0bar"; 时,我们可以说 p 指向一个长度为 3 的字符串; p+4 指向另一个字符串 :) - pmg
@pmg 确实。"foo\0bar"是一个包含两个字符串的字符串字面值,因此它不是一个字符串。是的,就是那么简单。 - Andrew Henle
2个回答

3

你想太多了。

"字符串是由连续字符序列组成的,以及包括第一个空字符在内的。"

来源: ISO/IEC 9899:2018 (C18), §7.1.1/1, 第132页

说“字符串”只延伸到第一个空字符。空字符之后可能存在的字符不是字符串的一部分。然而

"80) 字符串字面值可能不是字符串(参见 7.1.1),因为可以通过 \0 转义序列将空字符嵌入其中."

明确表示字符串字面值 可能 包含嵌入的空字符。如果包含,则字符串字面值作为一个整体不是字符串--字符串仅是字符串字面值前缀,直到第一个空字符为止。


0
让我们看一下在C18第6.5.1/3节中"字符串字面值"的定义:

"一个字符串字面值是一个由双引号括起来的零个或多个多字节字符组成的序列,例如 "xyz""

根据这个,一个字符串字面值只包含在引号中括起来的字符,即裸露的字符串内容。它没有附加的\0。 NUL字节稍后在翻译中添加,如第6.5.1/6节所述:

"在第7阶段的翻译中,将一个值为零的字节或代码附加到由字符串字面值或字面量生成的每个多字节字符序列。 80)"


让我们举个例子:

"foo" 是一个 字符串字面量,但不是一个 字符串,因为 "foo" 不包含一个 嵌入的 空字符。

"foo\0" 是一个 字符串字面量 和一个 字符串,因为字面本身在字符序列末尾包含一个空字符。


请注意,在将字符串文字更改为字符串时,您无需显式插入空字符到末尾。正如已经提到的那样,它会在程序翻译期间隐式添加。
也就是说,
const char *s = "foo";

等于

const char *s = "foo\0";

我承认,以下句子有些混乱和不太合逻辑:

"A string literal might not be a string (see 7.1.1), because a null character can be embedded in it by a \0 escape sequence."

更好的表达方式应该是:

"A string literal might not be a string (see 7.1.1), because a null character might not(或者说不需要)be embedded in it by a \0 escape sequence."

或者可以改为:

"A string literal might not be a string (see 7.1.1), because a null character can be embedded in it by a \0 escape sequence."


正如@EricPostpischil在他的评论中指出的那样,脚注的含义可能完全不同。

这意味着如果字符串字面量内部包含一个空字符,但不是在末尾,因为这是字符串所必需的,那么字符串字面量就不等同于字符串

例如: 字符串字面量

"foo\0bar"

不是一个字符串,因为它包含第一个空字符嵌入在字符串字面值中,但不在其末尾。


4
你漏掉了一个方面,或者至少没有说明清楚。由"abc\0def"定义的字符序列不是一个字符串,因为它没有以第一个空字符作为结尾。而77.11说:“字符串是一个以包括第一个空字符为止的连续字符序列。”这就是为什么注脚80说字符串字面量可能不是一个字符串:一个字符串字面量可能不符合以第一个空字符为结尾的规则。 - Eric Postpischil
@EricPostpischil 啊,这很有道理。我关注的是空字符本身的存在,而不是它的位置。是的,那么实际上,脚注就有意义了。我将您的输入纳入答案中。但尽管如此,我认为这个脚注并不十分清晰和傻瓜式,正如这个问题所展示的那样。 :-) - RobertS supports Monica Cellio
@EricPostpischil 但这让我产生了另一个问题:根据那个定义,"abc\0\0" 是一个字符串吗? - RobertS supports Monica Cellio
1
“abc\0\0”在其第一个空字符后面有一个字符“\0”,因此该字符序列不符合字符串的规则。 - Eric Postpischil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接