为什么在 C 风格的字符串上使用 == 有效?
Why does using == on a C-style string work?
我的印象是没有为 C 风格的字符串定义比较运算符,这就是为什么我们使用像 strcmp()
这样的东西。因此,以下代码在 C 和 C++ 中是非法的:
if("foo" == "foo"){
printf("The C-style comparison worked.\n");
}
if("foo" == "bob"){
printf("The C-style comparison produced the incorrect answer.\n");
} else {
printf("The C-style comparison worked, strings were not equal.\n");
}
但我使用 GCC 在 Codeblocks 和 VS 2015 中测试了它,编译为 C 和 C++。两者都允许代码并产生正确的输出。
比较 C 风格的字符串合法吗?还是允许此代码工作的非标准编译器扩展?
如果这是合法的,那么为什么人们在 C 中使用 strcmp()
?
编译器可以自由使用字符串驻留,即通过避免重复相同的数据来节省内存。比较相等的 2 "foo"
个文字必须存储在您的案例中的相同内存位置。
但是,你不应该以此为规矩。 strcmp
方法在所有情况下都有效,而它是由实现定义的,你的观察是否适用于另一个编译器、编译器版本、编译标志集等。
该代码在 C 中是合法的。它可能不会产生您预期的结果。
字符串文字的类型在C中是char[N]
,在C++中是const char[N]
,其中N是字符串文字中的字符数。
"foo"
在 C 和 C++ 中分别是 char[4]
和 const char[4]
类型。基本上它是一个 数组 。当在 表达式 中使用时,数组会转换为指向其第一个元素的指针。因此在比较中,if("foo" == "foo")
字符串文字被转换为指针。因此,"address comparison".
比较中,
if("foo" == "foo"){
比较字符串文字的地址,可能相等也可能不相等。
相当于:
const char *p = "foo";
const char *q = "foo";
if ( p == q) {
...
}
C 标准不保证两个具有相同内容(此处为 "foo"
)的字符串文字的地址相等,它们位于同一位置。但实际上,任何编译器都会放置在同一地址。所以比较似乎有效。但是你不能依赖这种行为。
6.4.5,字符串文字 (C11, draft)
It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
同样,这个对比
if("foo" == "bob"){
...
}
相当于:
const char *x = "foo";
const char *y = "bob";
if("foo" == "bob"){
...
}
在这种情况下,字符串文字将位于不同的位置并且指针比较失败。所以在这两种情况下,看起来 ==
运算符实际上用于比较 C-strings.
相反,如果您使用 数组 进行比较,它将不起作用:
char s1[] ="foo";
char s2[] = "foo";
if (s1 == s2) {
/* always false */
}
不同之处在于,当用字符串文字初始化数组时,它会复制到数组中。数组 s1
和 s2
具有不同的地址并且永远不会相等。但是在字符串文字的情况下,p
和 q
都指向相同的地址(假设编译器如此放置 - 如上所述不能保证)。
是copying/comparing字符串的地址,不是字符串的内容。
比较地址是一个有效的操作
我的印象是没有为 C 风格的字符串定义比较运算符,这就是为什么我们使用像 strcmp()
这样的东西。因此,以下代码在 C 和 C++ 中是非法的:
if("foo" == "foo"){
printf("The C-style comparison worked.\n");
}
if("foo" == "bob"){
printf("The C-style comparison produced the incorrect answer.\n");
} else {
printf("The C-style comparison worked, strings were not equal.\n");
}
但我使用 GCC 在 Codeblocks 和 VS 2015 中测试了它,编译为 C 和 C++。两者都允许代码并产生正确的输出。
比较 C 风格的字符串合法吗?还是允许此代码工作的非标准编译器扩展?
如果这是合法的,那么为什么人们在 C 中使用 strcmp()
?
编译器可以自由使用字符串驻留,即通过避免重复相同的数据来节省内存。比较相等的 2 "foo"
个文字必须存储在您的案例中的相同内存位置。
但是,你不应该以此为规矩。 strcmp
方法在所有情况下都有效,而它是由实现定义的,你的观察是否适用于另一个编译器、编译器版本、编译标志集等。
该代码在 C 中是合法的。它可能不会产生您预期的结果。
字符串文字的类型在C中是char[N]
,在C++中是const char[N]
,其中N是字符串文字中的字符数。
"foo"
在 C 和 C++ 中分别是 char[4]
和 const char[4]
类型。基本上它是一个 数组 。当在 表达式 中使用时,数组会转换为指向其第一个元素的指针。因此在比较中,if("foo" == "foo")
字符串文字被转换为指针。因此,"address comparison".
比较中,
if("foo" == "foo"){
比较字符串文字的地址,可能相等也可能不相等。
相当于:
const char *p = "foo";
const char *q = "foo";
if ( p == q) {
...
}
C 标准不保证两个具有相同内容(此处为 "foo"
)的字符串文字的地址相等,它们位于同一位置。但实际上,任何编译器都会放置在同一地址。所以比较似乎有效。但是你不能依赖这种行为。
6.4.5,字符串文字 (C11, draft)
It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.
同样,这个对比
if("foo" == "bob"){
...
}
相当于:
const char *x = "foo";
const char *y = "bob";
if("foo" == "bob"){
...
}
在这种情况下,字符串文字将位于不同的位置并且指针比较失败。所以在这两种情况下,看起来 ==
运算符实际上用于比较 C-strings.
相反,如果您使用 数组 进行比较,它将不起作用:
char s1[] ="foo";
char s2[] = "foo";
if (s1 == s2) {
/* always false */
}
不同之处在于,当用字符串文字初始化数组时,它会复制到数组中。数组 s1
和 s2
具有不同的地址并且永远不会相等。但是在字符串文字的情况下,p
和 q
都指向相同的地址(假设编译器如此放置 - 如上所述不能保证)。
是copying/comparing字符串的地址,不是字符串的内容。
比较地址是一个有效的操作