在我们编写程序时,大多数情况下都是函数传参,接收返回参数,但这中间有一定的操作系统内存传递原理,当你看完这篇文章你会发现,噢!原来这样使用会出错之类的感想!
最简单的,函数现场保护,通常操作系统会使用call指令来调用函数,用ret返回上一个函数,中间需要将上一个函数的执行情况,以及返回地址写入到寄存器(根据架构不同看CPU如何选择寄存器)当中,供ret指令使用!
考虑到看这篇文章的都是刚入门级别的所以就不从汇编角度来分析了!也不分析汇编代码之类的,这里就从最上层的术语讲解!
一.函数调用
int add(int c){
c = c+1;
return c;
}
int main(){
int y = add(2);
}
以上有add函数,add函数负责将传递进来的值+1
当我们调用add函数时,如果给定的是立即数(也就是常数123456但不是变量)那么立即数会被放入代码段的低位则本身不开辟地址空间,比如01010001前面0101000是函数传参,后面的01二进制到十进制就是1那么就是将01传递给参数!
如果不是立即数,是变量,比如:
int add(int c){
c = c+1;
return c;
}
int main(){
int i = 2;
int y = add(i);
}
那么就会使用寻址汇编指令先将i的地址里的值取出放入到临时通用寄存器(看架构)里在将值写入到参数内存里去
小知识:
CPU不可以直接写入,因为内存单元不归CPU管控,CPU只能先取出来值,然后在告诉内存芯片这个值应该给谁,由内存芯片来做
二. 线程传参
线程A
int add(int* c){
for(int i = 0;i<=10000;++i); //sleep
c = c+1;
return c;
}
线程B
int add1(){
int c = 0;
add(&c);
return c;
}
这个函数看起来没有什么问题,但会中断
原因:
在线程传参时一般参数是指针(操作系统规范) 指针指向值,如果这个时候b线程给a线程的是栈数据(如果双方时间轴不同),那么b线程结束掉了,b线程的栈内存被回收了,而a线程里的指针指向b线程,这时a线程操作指针就会出现地址非法,所以我们应该注意,在传参时一定要使用malloc来分配一个内存,然后写入值,在将地址传递给下一个指针就可以了!
当然加锁也是一种解决办法
注意int*和其他类型可以使用memcpy函数来copy
memcpy(a,b,sizeof(int));//将int b 的值copy给a
传递好了之后在指针指向就可以了
int *a = malloc
memcpy..
int *b = *a; //解引用将a指向的值返回回来
str可以使用strcpy!
三. 指针返回参数
int *add(int a, int b){
int size = a+b;
return size;
}
int main(){
int *Size = add(2,3);
printf("%d",Size);
}
输出:
随机值
原因:
add函数返回的是指针类型的,而非栈类型,编译器在返回时会返回size的地址,而add函数里的size恰巧是栈类型,所以在return前此内存就会被释放,原因:栈返回类型时:return时CPU会把值取出放入寄存器在带回,而返回地址时,内存恰巧被释放了,乱内存,所以Size指向的是被释放的内存段乱地址!