看看坛友中还有多少是和我一样长年战斗在 C 上的,答对三个就算

2018-09-25 17:36:23 +08:00
 dingzs3

#include<stdio.h>

#include<string.h>

#include<stdlib.h>

void main()

{

    char *p1=(char *)malloc(1024);  //1k

    char *p2=(char *)malloc(4096);  //4k

    memset(p2,0,4096);

    char *p3=(char *)malloc(8192);  //8k

    char *p4=(char *)malloc(128*1024*1024); //128k

    char *p5=(char *)malloc(115*1024);//115k

    printf("p1=%p p2=%p p3=%p p4=%p p5=%p\n",p1,p2,p3,p4,p5);


    memset(p2,'1',20);

    free(p2);

    memset(p2,'y',10);

    printf("p2=%s\n",p2);

    free(p3); //core

    free(p5);

    free(p1);

}

输出: p1=0x1c60010 p2=0x1c60420 p3=0x1c61430 p4=0x7ffbabc2b010 p5=0x1c63440

p2=yyyyyyyyyy?

Segmentation fault (core dumped)

1.p2-p2 为啥不是 1024

2.p4 的地址为啥和其它的不一样

3.为啥在 free(p2)之后还能读写 p2

4.为啥 p2 的打印不是 yyyyyyyyyy1111111111

5.为啥在 free(p3)的时候会 core

8077 次点击
所在节点    程序员
76 条回复
dingzs3
2018-09-26 09:27:26 +08:00
@JeffKing 写错了是 p2-p1 的结果为啥不是 1024
这是 glibc 的内存分配机制问题,小内存是调用的 brk 吧,大内存用的是 mmap,brk 直接对应内核做 e_data 的偏移,所以小内存的虚拟地址是 data 段增长的,而大内存的地址则是在堆栈之间获取一个地址用
此时 p2 的内存对应的物理内存是没有释放的,所以可以读写,且虚拟地址也是在用户空间的。
dingzs3
2018-09-26 09:30:29 +08:00
@zmj1316 哈哈哈,C 和 C++不分家的,面向对象也就是思想和编译器(语法)上的差距
where2go
2018-09-26 10:09:11 +08:00
@dingzs3
$ cat >> a.c << "EOF"
void main(){}
EOF
$ gcc -Wall a.c
a.c:1:6: warning: return type of 'main' is not 'int' [-Wmain]
void main(){}
^~~~
dingzs3
2018-09-26 10:18:28 +08:00
@where2go 好吧,我错了,忽略 warning,的确是不对的
ioth
2018-09-26 10:40:47 +08:00
c 的技巧似乎在 java 里面没有用了。
reus
2018-09-26 11:34:33 +08:00
全都是未定义行为,有什么好讨论的。
malloc / free 的行为和内存分配器的实现有关,换一个实现或者换一个版本,可能就不一样了,glibc 就能保证一样?不能,因为没有谁说了保证,那你就不能依赖它,因为它是未定义行为。
有些 C/C++ 项目不敢升级编译器版本,就是因为太过于依赖这些未定义行为,导致编译器一升级,这些行为就变了,代码就炸了。
陋习。
zwh2698
2018-09-26 13:03:48 +08:00
@dingzs3 8 年坚持不错啦,我也是 c++出身,后来更多 hybrid. 其实答案是 unoin, 因为编译器一直有一个思想就是编译时更多的发现问题,指针太暴力。其实这个也是其他语言 var 关键字模拟,当然 c++中的 var 是另一回事了。希望坚持,底层开发来钱慢,难度大,要么灰产/黑,要么坚持系统编程。
dingzs3
2018-09-26 14:06:51 +08:00
@zwh2698 的确是,以前我学习汇编,就干过逆向工程的活,看那些黑产来钱快。
but0n
2018-09-26 14:10:26 +08:00
@zwh2698 #19 void*?
zwh2698
2018-09-26 14:57:52 +08:00
@but0n unoin
bluefalconjun
2018-09-26 15:26:25 +08:00
go 语言了解一下... :)
不明白这段 code 有什么讨论的意义...
@crazyneo @shilyx @reus 都说得很好啊...
BTW, 芯片公司 sdk 开发了解一下, 这么写 code, 自己 debug 的时候 分分钟飞到不知道哪里去了...
myself659
2018-09-26 15:41:02 +08:00
这级别过了不前前前公司的编程考试
dingzs3
2018-09-26 16:52:01 +08:00
@bluefalconjun
@myself659 这个不是为了实现什么功能,也不是实际生产环境用的,只是随便写的程序来验证自己对于知识的理解对不对而已啊,可能一般的 C 开发人员不需要理解这些,就比如 go,它就是尽量屏蔽对于底层的了解,性能也不算太低,开发效率很高。但是在有些场景下,比如 DNS 服务器开发(我现在干的),面对的要求是单机几百万 QPS 的并发,那么我们就必须了解自己的代码是怎么运行的,使用的库是如何实现的,操作系统层面是怎么做的,如何让 CPU 更好的并发执行。场景不一样吧。

但是一旦你理解了这些,那么学其它语言就相当容易了,比如 go,你就能理解它的内存回收机制,他的基本数据类型是如何实现的,它的 goroutine,chan 底层是啥等等。
zhicheng
2018-09-26 17:25:27 +08:00
你的这个代码,不是什么底层,也不是什么知识,更不能在生产环境使用,除了那种要求指出错误的面试题,不应该用在任何地方。C 语言里明确表明了是未定义行为,就不要花时间去研究如果这样做了会是什么样的结果,因为它真的可以是任何行为,C 语言是一个标准并不是一个 C 实现。

初级工程师总觉得“了解”一点儿别人不知道的很厉害,殊不知这是高级工程师尽量避免的情况。

未定义行为的代码 == 错的代码
reus
2018-09-26 17:27:24 +08:00
@dingzs3 我不需要了解这些 C 的未定义行为,照样可以理解 go 的 GC 等底层实现。你这些知识,是很易碎的。
dingzs3
2018-09-26 17:38:52 +08:00
@zhicheng
@reus 我们不是为了争论而争论啊,都说了只是看看有多少是长期做 C 的,这个代码很简单,只是为了看看有哪些人是能够从这个代码看到 glibc 库的内存分配机制,linux 内核的内存分配机制。我知道现在的趋势是尽量多关注业务,而不是陷入底层这个无底洞,所以我上面也是说了,如果像我这样陷进去的还好不好找工作,长期干 C 的还多不多。
我也没有说必须懂 c 才能懂 go 啊,只是说如果懂 C 的人可能会比不懂的人更好的理解 go 的机制,但也只是可能,并不是绝对的,就好象说已经懂一门语言的人去学习新的语言,总是比一个啥开发语言都不会的人,稍微有点优势而已。
zhicheng
2018-09-26 17:51:39 +08:00
我并没有争论,我只是在说你在误人子弟。
dingzs3
2018-09-26 17:58:41 +08:00
@zhicheng 好吧,我错了,我问个问题已经变成误人子弟了,难道我出个题应该这样说:懂 glibc 和内核原理的人进来,不懂的别看。技术上没有啥不能讨论的啊,了解的可以讨论一下,不了解的可以略过,或者是看着乐呵乐呵。
zhicheng
2018-09-26 18:07:28 +08:00
因为你的代码本来就是错的,你在为错的代码强行找原因,你今天的 glibc 版本是这个行为,下一个可能是另一个行为,甚至不同的编译参数产生的行为也不一样。你要讨论 glibc 和 linux 就直接讨论,出个错的题目要“考”一下别人也是有趣。

如同法律上写了红灯不要过马路,你非要去讨论什么样的情况下红灯可以过马路,抱歉我理解不了这种行为。
dingzs3
2018-09-26 18:11:02 +08:00
@zhicheng 可能是我表述的有问题吧,我没有考的意思,只是希望讨论一下,这个特意写错的代码只是为了验证库和内核的机制而已,希望拿出来讨论。如果让你这样理解,那我道歉。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/492448

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX