自己实现了一个内存池,
void *my_malloc(uint size)
{
void *p1;
......; //从内存池中申请了一块内存
return p1;
}
int main(int argc, char *argv[])
{
......;
void *p2 = malloc(100);
}
通过GDB调试,在my_malloc函数里,p1的值是0x7ffff430c0b0,
可main函数里赋值给p2后,p2的值竟然成了0xffffffff430c0b0,高位全自动补1了,
这是为什么啊?
测试环境: LINUX 2.6.32(64Bit), gcc 4.4.3
这种情况编译器有警告,可我没注意,程序运行起来肯定就挂了!
On 8月1日, 下午10时58分, Li Haifeng <omy...@gmail.com> wrote:
> 2011/8/1 rclijia <rcli...@gmail.com>
也怪我没描述的特别详细,这两个函数不在同一个源文件里,
否则,我想很多人一下就能看出问题所在了!
自己问,自己答:
原因如下:
在libnids.c中,没有包含my_malloc()函数的声明,编译器就会假定类型为: int my_malloc().
我是这么想的,不知道对不对?!
On 8月3日, 下午3时10分, 宋劲杉 <songjins...@gmail.com> wrote:
> 类型转换不对,出运行时错误是肯定的。
> 正因为链接能链接上,所以才能编译出程序来,所以才有机会出运行时错误。
>
> 2011/8/3 Li Haifeng <omy...@gmail.com>
>
>
>
>
>
>
>
>
>
> > 2011/8/3 rclijia <rcli...@gmail.com>
> Email:songjins...@tvie.com.cn <songjins...@gmail.com>
> 公司网站:http://www.tvie.com.cn
编译时,只是针对本文件内的代码,
由于碰到了未定义的函数,而且还没有声明,那返回值无法事先预知啊,
此时编译器默认返回值为int型,
但实际上代码为:void *p = my_malloc(100), 本意是想得到64位的数据,
编译器生成的实际汇编代码只会复制低32位数据,
实际链接时,发现了my_malloc()的实际定义和之前猜测的不一样,
编译器会打印警告信息,但错误已经发生了,没机会改了。
链接器只是把my_malloc的函数入口地址填补上而已,
我是这么想的,不知道对不对?!
On 8月3日, 下午5时48分, 宋劲杉 <songjins...@gmail.com> wrote:
> 那你觉得是怎么样的呢?
>
> 2011/8/3 Li Haifeng <omy...@gmail.com>
>
>
>
>
>
>
>
>
>
>
>
> > 2011/8/3 rclijia <rcli...@gmail.com>
宋老师,您的教材里有提过隐式声明会当成int func(...) 的规则。请问这个规则为什么会存在阿?感觉除了增加出错率,这玩艺没有任何好处么?
为什么要声明呢?是因为在调用之前编译器找不到函数的声明,所以会编译出错,既然能编译通过,说明在调用之前,编译起已经扫描到原函数了,不用再次声
明。
"
你的这两句话,第一行是OK的,
第二行的后半句就说不通了。
编译的时候找不到my_malloc()的声明与定义,但此时还要用到my_malloc的返回值,
那从返回值的起始地址开始,往后是读取1个字节,还是2个字节,还是4个字节......?不确定啊
这个时候和预留函数入口地址还不一样,此时此刻是必须要生成实际汇编指令的,
只能假定个返回值类型,编译器就默认为Int, 取4个字节(但这里错了,实际是想取8个字节),然后生成了对应的汇编代码,
函数的入口地址此时还未知,这个可以留个位置与记号,后面的链接器会补充。
把所有的.c文件都编译完后,链接器会把所有的.o文件链接成一个可执行文件,
这其中会把之前预留的my_malloc()函数的入口地址补充上,所以程序才能运行起来,
但运行的时候,执行到这一句:
void *p = my_malloc(100);
实际的效果已经类似 : void *p = (int) my_malloc(100), 高32位数据被截断了,
再往下执行, 只要操作p指针,就可能会段错误。
为什么是可能段错误呢?
一个侥幸的结果就是,通过my_malloc()申请的内存在堆上,一般都是类似0x6xxxxx开头的地址,
地址总位数不超过32位,那程序运行就没问题了,
但这是个"不定时的定时炸弹",随时会爆炸的!
我觉得应该是这么回事。
我是宋老师当年在亚嵌的学生,呵呵!
On 8月4日, 上午9时17分, 宋劲杉 <songjins...@gmail.com> wrote:
> rclijia和siqiao chen是对的。
>
> 2011/8/4 Li Haifeng <omy...@gmail.com>
>
>
>
>
>
>
>
>
>
> > 2011/8/4 siqiao chen <siqiaoc...@gmail.com>
>
> >> 宋老师,您的教材里有提过隐式声明会当成int func(...) 的规则。
>
> >> 请问这个规则为什么会存在阿?感觉除了增加出错率,这玩艺没有任何好处么?
>
> > 不明白为很么会增加出错率。
>
> > 声明只是在编译的时候起作用,告诉编译器,这个函数是在其他文件,或者是在后面定义的,暂时先不用管。
>
> > 为什么要声明呢?是因为在调用之前编译器找不到函数的声明,所以会编译出错,既然能编译通过,说明在调用之前,编译起已经扫描到原函数了,不用再次声明。
>
> > 按照lz说的情况,不声明照样 能编译过去,你再声明,就没有任何必要。
>
> > 至于声明的返回值问题。
>
> > 1。c语言不是c++,不支持重载,它被汇编后,函数的名字是不更改的;并不像c++那样汇编结束后函数的名字前面需要加上返回值类型,后面需要加上参数的个数以及参数的类型。
> > 2。它并不影响最终结果,换句话说,它不影响最终的可执行文件。
>
> > 因此,lz所述的错误根源不在于你声明的时候,返回值类型匹不匹配。
>
> > 如果有错误,请批评指正。
>
> >> 2011/8/3 宋劲杉 <songjins...@gmail.com>
>
> >>> 那你觉得是怎么样的呢?
>
> >>> 2011/8/3 Li Haifeng <omy...@gmail.com>
>
> >>>> 2011/8/3 rclijia <rcli...@gmail.com>
void *p = my_malloc(100);
指针变量p 在栈上, 分配了8个字节空间。
但是在赋值的时候,因为编译器认为是int,
所以生成的汇编代码只能是类似 MOV QWORD PTR [RSP + x], EAX
楼主正确的地址是 0x7ffff430c0b0 ,也就是eax里面是F430C0B0,最高位(符号位)是1,
所以扩展为QWORD就成了 0xFFFFFFFF F430C0B0.
按照64bit 系统的内存分配
(http://www.ualberta.ca/CNS/RESEARCH/LinuxClusters/mem.html#mmap),
这个地址显然在512G 以上,一定是内核地址空间的,所以一定会出现访问异常。
2011/8/3 rclijia <rcl...@gmail.com>: