C語言return返回值深入理解


  C語言使用return關鍵字返回函數值,可以很好對函數做封裝,此處的疑問是:函數內部創建的變量都是局部變量,即私有的,作用域就在函數之內,為什么卻可以把值傳給調用函數?

  解釋這個問題還需要從C語言調用函數傳參類比來說,C語言傳參調用時,可以采用傳值和傳指針兩種方式。

  傳值的形式:只是將參數值的拷貝傳給函數,並非參數本體,如:

 1 int test_func(int i)
 2 {
 3     i++;
 4     printf("Function i : %d\n", i);
 5     return 0;
 6 }
 7 
 8 int main()
 9 {
10     int a = 10;
11     printf("Main Pre: %d\n", a);
12     test_func(a);
13     printf("Main Now: %d\n", a);
14 
15     return 0;
16 }

  傳指針形式:直接傳給函數的是變量的地址,由於被調函數在參數指針的作用域之內,此時直接改變變量的本體。

 1 int test_func(int *i)
 2 {
 3     (*i)++;    //注意:++的優先級比*高
 4     printf("Function i : %d\n", *i);
 5     return 0;
 6 }
 7 
 8 int main()
 9 {
10     int a = 10;
11     printf("Main Pre: %d\n", a);
12     test_func(&a);
13     printf("Main Now: %d\n", a);
14 
15     return 0;
16 }

同理,函數返回也有兩種形式。

1、函數返回變量值

  此時,返回變量值的方式與函數調用傳值同樣的道理,在函數結束返回時,將局部變量值拷貝給一個臨時變量,然后將這個臨時變量返回給調用函數。因此,即使局部變量在返回時已經釋放內存,也不影響返回的變量值。

 1 int test_func()
 2 {
 3     int i = 2;
 4     printf("Function i : %d\n", i);
 5     return i;
 6 }
 7 
 8 int main()
 9 {
10     int a = 0;
11     a = test_func();
12     printf("Main Now: %d\n", a);
13 
14     return 0;
15 }

從匯編的角度來看源代碼:

由以上看出:返回變量值的時候,直接將局部變量的值傳給了了寄存器eax,也就是說,函數返回以后,雖然局部變量已被釋放,但是eax里面的還有一個值的拷貝。

2、函數返回地址

  此時注意:C語言的指針操作,大部分都是直接對指針指向的變量直接操作,函數內部的變量和指針一般分配在棧上,而棧上的數據都是臨時保存的,當函數返回時會自動釋放掉,因此如果直接返回一個棧上的指針,返回的值將不可預知。

 1 int *test_func()
 2 {
 3     int local_data = 10;
 4 
 5     printf("Function local_data : %d\n", local_data);
 6 
 7     return &local_data;
 8 }
 9 
10 int main()
11 {
12     int *main_data = NULL;
13 
14     main_data = test_func();
15 
16     printf("Return data: %d\n", *main_data);
17 
18     return 0;
19 }

 從匯編語言角度查看源碼:

由以上看出:返回指針的時候,用的是指令lea,這條指令的作用是,將[ebp-4](此單元對應的是變量local_data在棧上的數據存儲位置)這個數據單元的地址傳給eax寄存器,但是像這樣在棧上開辟出來臨時存儲數據的單元,只要調用函數結束,就會釋放掉里面的數據,因此雖然返回了一個指針,指針指向的數據卻已經被系統銷毀了,這就導致返回的指針指向不可預知的數據。

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM