包含'\ 0'的字符串文字 - 为什么它们不一样?

问题描述:

所以我做了如下试验:包含' 0'的字符串文字 - 为什么它们不一样?

char* a = "test"; 
char* b = "test"; 
char* c = "test\0"; 

而现在的问题:

1)能够保证所有的a==b我知道我在比较地址。这并不意味着要比较字符串,但相同的字符串文字是否存储在单个内存位置

2)为什么不是a==c?编译器不应该看到它们指的是相同的字符串吗?

3)c的末尾是否附加了\0,即使它已经包含了一个?

我不想问这3个不同的问题,因为他们似乎有点相关,对不起'布特那。

注:标签是正确的,我对C++感兴趣。 (虽然请说明C的行为是否不同)

+7

应该是'char const * a = ...'。 –

+0

a和b具有相同的值,但这并不一定意味着它们是_same_字符串。 –

+0

@HunterMcMillen - 其实这就是它的意思。 –

是否保证a == b?

号但它是由§2.14.5/ 12允许:

是否所有字符串文字是不同的(即,被存储在非重叠的对象)是实现定义。试图修改字符串文字的效果是未定义的。

而且,你可以使用char*代替char const*最后一句看到的是一个麻烦的食谱(和你的编译器应该拒绝它,请确保您有打开了警告,并选择高一致性水平)。

为什么不是a == c?编译器不应该看到它们指的是相同的字符串吗?

不,他们不需要指的是相同的字符数组。一个有五个要素,另外六个要素。一个实现可以将这两个存储在重叠存储中,但这不是必需的。

在c的末尾添加了一个\ 0,即使它已经包含了一个?

是的。

+0

也许值得说明的是''test''是一个文字'char const [5]'在A和B *为什么会重叠但C不会的背景下。 – AJG85

+0

谢谢。还有一个问题。如果我用'strcmp'比较'a'和'c',它会说它们是否相等?另外,是否允许'a == c'? – AMCoder

+0

@ AJG85为什么不会'c'重叠?标准明确地允许它(引用在答案中,并且不限于相同的文字),并且程序不能在不调用未定义的行为的情况下区分差异。 –

1 - 绝对不是。如果编译器选择共享相同的静态字符串,则可能会出现一个== == b。

2 - 因为它们不是指相同的字符串

3 - 是的。

这里的C和C++的行为没有什么不同,只是C++编译器应该拒绝赋值给非const char *。

+0

字符串文字转换为char *转换已被弃用,但在C++中不被禁止。 –

+0

@james它在C++中被禁止11 –

+0

@ JohannesSchaub-litb:没办法!这是我一整天听到的最好的消息。 g ++ 4.7,clang 3.1和VC11都接受这种转换,但我期待他们不会这样做:-) –

这里的问题是你在混合指针和文本等价的概念。

当你说a == ba == c你问的指针是否指向相同的物理地址。测试与指针的文本内容无关。

为了让文字等价,你应该使用strcmp

+0

请注意'strcmp'会停止在* first *零,所以字符串'a'和'c'会比较相等,即使一个比另一个长。 –

+0

@MarkRansom它在文本意义上的等效长度,尽管这是strcmp会考虑的。也许我应该扩大我的答案到这里可能很重要的三个领域:指针等价,文本等价和内存等价 – JaredPar

+0

-1抱歉,但我有一个指针比较,因为我想比较指针。这就是问题所在。 – AMCoder

1)能够保证所有的A == B'

不是。请注意,您正在比较地址,他们可能指向不同的位置。大多数智能编译器会折叠这个重复的文字常量,因此这些指针可能会相等,但又不会被标准保证。

2)为什么不a == c?编译器不应该看到它们指的是相同的字符串吗?

您试图比较指针,它们指向不同的内存位置。即使你在比较这些指针的内容,它们仍然是不相等的(见下一个问题)。

3)在c的末尾是否附加了一个\ 0,即使它已经包含了一个?

是的,有。

+0

我知道我在比较地址,请问这个问题。要清除这个问题 - 相同的字符串文字位于相同的内存中吗? – AMCoder

+0

我猜'a'和'c'的指针可以相等。一个程序不能在不调用UB的情况下区分它们。 –

+0

@R。马丁尼费尔南德斯:这是一个好点,我相信你是对的。 –

如果你正在做指针比较比!= b,b!= c,并且c!= a。除非编译器足够聪明才能注意到你的前两个字符串是相同的。

如果你做了一个strcmp(str,str),那么你所有的字符串都会作为匹配返回。

我不确定编译器是否会向c添加一个额外的空终止符,但我猜测它会。

首先注意,这应该是const char *,因为这是字符串文字衰减到的。

  1. 两者都创建用't''e''s''t'用'\ 0'(长度= 5)覆盖的初始化数组。比较平等只会告诉你他们是否都以相同的指针开始,而不是如果他们有相同的内容(尽管在逻辑上,这两个想法相互依存)。
  2. A不等于C,因为相同的规则适用,a ='t''e''s''t''\ 0'和b ='t''e''s''t'' \ 0''\ 0'
  3. 是的,编译器总是这样做,你不应该在做这样的字符串时明确地做。但是,如果您创建了一个数组并手动填充它,则需要确保添加\ 0。

请注意,对于我的#3,const char [] =“Hello World”也会在最后自动获得\ 0,我正在重新手动填充数组,而不是让编译器解决它。

+0

我不认为'a'和'c'保证不相等。该标准允许实现将文字存储在重叠存储中,并且程序无法在不调用UB的情况下区分这些差异。 –

+0

我确实同意你的检查,这是一个我没有听说过的点。我的观点仍然是,编译器肯定会在情况2中放置两个空终止符,尽管这会使操作不平等,即使读取字符串和检查它们的指针也是相等的。另外,如果您记录了为c创建的字符串的长度,则可以安全地读取strlen()的过去1,并且不能为a(除非它们与您所说的位置相同,但是您不会)不能保证)。 –

+0

*即使编译器将它们存储在相同的位置*,“a [5]”(它尝试读取与c [5]'相同位置的值)会调用未定义的行为,因为“a”指向一个大小为5的数组。没关系的是恰好有另一个数组放在同一个地方。 –

正如其他答案中所说的几次,你在比较指针。但是,我会补充说strcmp(b,c)应该是真的,因为它在第一个\0停止检查。