herozem
V2EX  ›  C

C 语言中"=="的用法的几个问题?

By herozem at 2015 年 4 月 2 日 · 3178 次点击

先看测试用例:

#include <stdio.h>

int main(int argc, char *argv[])
{
  char *s = "hello";
  char *str = "hello";

  printf("compare pointers: ");
  s == str ? printf("y") : printf("n"); #(1)
  printf("\ncompare arguments: ");
  argv[1] == argv[2] ? printf("y") : printf("n"); #(2)
  printf("\nuse strcmp :");
  strcmp(&argv[1], &argv[2]) ? printf("y") : printf("n"); #(3)

  return 0;
}

运行结果:

$ ./a.out tmp tmp
compare pointers: y
compare arguments: n
use strcmp :y

确切的来说是想解决一些关于C和内存知识的问题:

在代码中, (1)比较的两个字符串, s和str在内存中是不同的指向char的指针, 但是他们指向的内容实际上是同一处?

(2)中比较的内容结果是不相等, "=="号比较的是所给参数的内存地址吗?
(3)的输出结果为y, 所以strcmp比较的是指针所指向的内容?

第 1 条附言  ·  2015 年 4 月 2 日
顺便希望大家能够推荐一些关于C和内存的书?我对这一块不熟悉
30 条回复  •  2015-04-03 00:23:24 +08:00
Andiry
   1
Andiry  
   2015 年 4 月 2 日
1) s 和 str是常量指针,指向同一个地址,所以s == str
2) Yes
3) Yes
zhicheng
   2
zhicheng  
   2015 年 4 月 2 日 via Android
1,是
2,是
3,是
herozem
   3
herozem  
OP
   2015 年 4 月 2 日
g5tf87
   4
g5tf87  
   2015 年 4 月 2 日   ❤️ 2
(1)里两个hello被编译在全局数据区,应该是被编译器优化为同一个地址,所以s和str两个指针指向的内容是一样的,输出为y。
(2)里面两个参数由于函数调用,其内容先后被存入栈上,所以argv[1]和arg[2]也是指针,指向的内容是不一样的,输出为n。
(3)通过字符串比较函数,比较字符串的内容,argv[1]和arg[2]指向的内容是一样的,所以输出为y。

一点粗浅见解,如有错误,希望高手指导交流~~~
wartime
   5
wartime  
   2015 年 4 月 2 日
1. s 和 str 指向同一字符串常量, 地址值相等 (编译时确定);
2. 命令行参数不同,内存地址不同;
3. strcmp 比较两块内存里从第一个字节开始,到值为'\0'结束的字符串是否相等, 有可能溢出;

如果定义成:
char s[] = "hello";
char str[] = "hello";
s != str, 此时s和str会被分配size为strlen("hello") + 1的新内存地址。
liuhaotian
   6
liuhaotian  
   2015 年 4 月 2 日   ❤️ 1
是的。比较的是指向内容。
The C library function int strcmp(const char *str1, const char *str2) compares the string pointed to by str1 to the string pointed to by str2.

顺便问一下 markdown这个代码高亮是怎么做到的?
herozem
   7
herozem  
OP
   2015 年 4 月 2 日
@liuhaotian 三个反单引号(数字键1左边那个), 后接bash、c、java之类的, 代码完以后另起一行再接三个反单引号

```bash
```bash
#不知道嵌套会被解析成什么样子?
```
```
mcone
   8
mcone  
   2015 年 4 月 2 日   ❤️ 1
如果我没记错的话,你在(1)里面的这种比较是很危险的,不同编译器在不同优化等级下面输出的结果很可能不一样(undefined behavior?)

好久没用过这个了,如有错误望楼下指出!
herozem
   9
herozem  
OP
   2015 年 4 月 2 日
@wartime 我试了一下,对于

```c
char s1[] = "hello";
char s2[] = "hello";
```

无论是使用s1 == s2 还是 strcmp(s1, s2) 结果都是n, 这其中的原因是?
herozem
   10
herozem  
OP
   2015 年 4 月 2 日
@herozem 不过回复好像不支持Markdown, 或者是我打开方式不正确 :(
herozem
   11
herozem  
OP
   2015 年 4 月 2 日
@mcone 这个我不太清楚, 不知道有没有相关的讲解的书籍或资料
bugeye
   12
bugeye  
   2015 年 4 月 2 日
用gcc -S xxx.c 生成汇编,然后看汇编就明白了
$ cat test.s
.file "test.c"
.section .rodata
.LC0:
.string "hello"
.LC1:
.string "compare pointers: "
.LC2:
.string "y"
.LC3:
.string "n"
.LC4:
.string "\ncompare arguments: "
.LC5:
.string "\nuse strcmp :"
.text
.globl main
.type main, @function
main:

看吧,只有一个"hello",所以两个指针的内容是一样的。但这种比较方法是危险的。如果生成的汇编很傻,那么结果就变了。
herozem
   13
herozem  
OP
   2015 年 4 月 2 日
@bugeye 不懂汇编, 没想到可以这样看 :(
walleL
   14
walleL  
   2015 年 4 月 2 日
strcmp(&argv[1], &argv[2]) ? printf("y") : printf("n");

大家都没发现这一行有问题吗?
1. argv[1] 已经是指向第一个参数字符串的指针了,&argv[1] 是干嘛呢
2. strcmp() 的返回值为0时才表示相等啊

所以这样才对吧:
strcmp(argv[1], argv[2]) == 0 ? printf("y") : printf("n");
walleL
   15
walleL  
   2015 年 4 月 2 日
@herozem 所以9楼的问题也是 strcmp() 返回值判断的原因吧
hualuogeng
   16
hualuogeng  
   2015 年 4 月 2 日
@herozem 请注意strcmp在字符串相等时,返回值是0,所以你用strcmp作为条件表达式的条件时,结果和你要的是相反的。
原文中的3,之所以相等,是因为还是比较的指针本身的值,因为不相等,所以才printf("y")
这也就能够解释你在9楼的疑问了。
hualuogeng
   17
hualuogeng  
   2015 年 4 月 2 日
上一条回复中 "原文中的3,之所以相等" 应表述为”原文中的3,之所以输出y"
herozem
   18
herozem  
OP
   2015 年 4 月 2 日
@walleL :) thank you so much! &argv[1]确实是不对的
herozem
   19
herozem  
OP
   2015 年 4 月 2 日
@hualuogeng 嗯, 是这样的, 谢谢
hualuogeng
   20
hualuogeng  
   2015 年 4 月 2 日
@walleL 你也发现这个问题了。

@herozem 另外,关于C的内存和指针,我记得有一本《C缺陷和陷阱》还不错。还有《专家编程》《C和指针》也不错
bugeye
   21
bugeye  
   2015 年 4 月 2 日
@herozem 我觉得如果你读过汇编,就知道C语言实质上是一种可以跨平台的高级宏汇编。所以想搞清楚这些底层的问题,最好是去学汇编。

但是。。。。。按软件业的现状看,还是把时间花在能快速原型,能快点做项目的语言为佳。就算用C语言也没必要搞清楚这些东西,只要记得比较字符串strcmp是正道就行。没必要浪费时间在这些底层细节上。这些细节要想100%搞清楚,得学计算机组成原理了。
herozem
   22
herozem  
OP
   2015 年 4 月 2 日
@bugeye 是啊。。所以我觉得到C语言不能再往下了(汇编什么的), 虽然说越往下学对计算机理解的越清楚。。。
hualuogeng
   23
hualuogeng  
   2015 年 4 月 2 日
@herozem @bugeye 看你用C语言完成什么样的工作了,如果是偏底层的,了解汇编是有必要的。而如果不是,大多数时候C都不是首选。
@herozem 刚才说的三本书中,学习内存和指针,首选《专家编程》吧。
jemyzhang
   24
jemyzhang  
   2015 年 4 月 2 日
编译优化的关系, 优化后s和str被指向同一个地址, 所以s == str成立
ZyZyZzz
   25
ZyZyZzz  
   2015 年 4 月 2 日
@hualuogeng “原文中的3,之所以输出y,是因为还是比较的指针本身的值”
比较的不是俩指针所在的内存地址嘛_(:з」∠)_?

还有这里用VS2010带的编译器编出的s和str指向的地址居然不一样……
hualuogeng
   26
hualuogeng  
   2015 年 4 月 2 日   ❤️ 1
@ZyZyZzz 我们的表述不一致,实际所指是一致的,如你图中所示,实际比较的是692381和692384。

常量的编译优化是编译器实现相关的,标准上没有规定,所以总是认为s和str指向相同的内存的想法是个坑。如你所说,VS2010就和GCC实现不一样。
21grams
   27
21grams  
   2015 年 4 月 2 日
第一个是编译器优化的,不能认为永远都成立。
xieyudi1990
   28
xieyudi1990  
   2015 年 4 月 2 日 via iPhone
@Andiry s 和 str 都是变量.
linux40
   29
linux40  
   2015 年 4 月 2 日
char *str = "hello"是不好的习惯。。。至于函数有返回值的,看书吧。。。
chisj
   30
chisj  
   2015 年 4 月 3 日
《C和指针》,《C陷进和缺陷》,《C专家编程》,但是这些都不如你撸几个实际项目学的东西来得靠谱。
© 2026 V2EX · 61ms · 3.9.8.5