網站首頁 編程語言 正文
一、函數參數
- 函數參數在本質上與局部變量相同在棧上分配空間
- 函數參數的初始值是函數調用時的實參值
- 函數參數的求值順序依賴于編譯器的實現
? ? ? ? 下面看一個函數參數的求值順序的示例:
#include <stdio.h>
int func(int i, int j)
{
printf("i = %d, j = %d\n", i, j);
return 0;
}
int main()
{
int k = 1;
func(k++, k++);
printf("%d\n", k);
return 0;
}
? ? ? ? ?輸出結果如下:
? ? ? ? ?這個示例說明函數參數的求值順序依賴于編譯器的實現。
二、程序的順序點
- 程序中存在一定的順序點
- 順序點指的是執行過程中修改變量值的最晚時刻
- 在程序到達順序點的時候,之前所做的—切操作必須完成
- 每個完整表達式結束時,即分號處
- &&,||,?:,以及逗號表達式的每個參數計算之后
- 函數調用時所有實參求值完成后(進入函數體之前)
? ? ? ? 下面看一個程序中的順序點示例:
#include <stdio.h>
int main()
{
int k = 2;
int a = 1;
k = k++ + k++;
printf("k = %d\n", k);
if( a-- && a )
{
printf("a = %d\n", a);
}
return 0;
}
? ? ? ? 輸出結果如下:
????????a-- && a?,對于?&& 運算符,每個操作數都是一個順序點。當程序從左往后執行時,a-- 對內存的修改必須立即完成,所以 a 就變成了 0。
? ? ? ? ? 為什么會輸出 6 呢?下面在 VS2012 里面運行代碼,進行反匯編操作:
? ? ? ? ?這段匯編代碼簡單的來說,就是先進行 + 操作,k = 2 + 2 = 4,然后進行兩次 ++ 操作,所以最終結果就是 6。
三、小結-上
- 函數的參數在棧上分配空間
- 函數的實參并沒有固定的計算次序
- 順序點是 C 語言中變量修改的最晚時機
四、調用約定
????????函數參數的計算次序是依賴編譯器實現的,那么函數參數的入棧次序是如何確定的呢?
當函數調用發生時
- 參數會傳遞給被調用的函數
- 而返回值會被返回給函數調用者
調用約定描述參數如何傳遞到棧中以及棧的維護方式
- 參數傳遞順序
- 調用棧清理
調用約定是預定義的可理解為調用協議
調用約定通常用于庫調用和庫開發的時候
- 從右到左依次入棧:_stdcall,_cdecl,_thiscall
- 從左到右依次入棧:_pascal,_fastcall
五、可變參數
? ? ? ? 計算平均值時,我們一般可以編寫成這樣:
#include <stdio.h>
float average(int array[], int size)
{
int i = 0;
float avr = 0;
for(i=0; i<size; i++)
{
avr += array[i];
}
return avr / size;
}
int main()
{
int array[] = {1, 2, 3, 4, 5};
printf("%f\n", average(array, 5));
return 0;
}
? ? ? ? 輸出結果如下:
C語言中可以定義參數可變的函數
參數可變函數的實現依賴于 stdarg.h 頭文件
- va_list? --? 參數集合
- va_arg --? 取具體參數值
- va_start? --? 標識參數訪問的開始
- va_end? --? 標識參數訪問的結束
? ? ? ? 下面看一個求可變參數平均值的代碼:
#include <stdio.h>
#include <stdarg.h>
float average(int n, ...)
{
va_list args;
int i = 0;
float sum = 0;
va_start(args, n);
for(i=0; i<n; i++)
{
sum += va_arg(args, int);
}
va_end(args);
return sum / n;
}
int main()
{
printf("%f\n", average(5, 1, 2, 3, 4, 5));
printf("%f\n", average(4, 1, 2, 3, 4));
return 0;
}
? ? ? ? 輸出結果如下:
六、可變參數的限制
- 可變參數必須從頭到尾按照順序逐個訪問
- 參數列表中至少要存在一個確定的命名參數
- 可變參數函數無法確定實際存在的參數的數量
- 可變參數函數無法確定參數的實際類型
? ? ? ? 注意:va_arg 中如果指定了錯誤的類型,那么結果是不可預測的。
七、小結-下
- 調用約定指定了函數參數的入棧順序以及棧的清理方式
- 可變參數是 C 語言提供的一種函數設計技巧
- 可變參數的函數提供了一種更方便的函數調用方式
- 可變參數必須順序的訪問,無法直接訪問中間的參數值
原文鏈接:https://blog.csdn.net/weixin_43129713/article/details/124163051
相關推薦
- 2022-08-21 caffe的python接口caffemodel參數及特征抽取示例_python
- 2022-07-10 緩存路由關聯的兩個生命周期activated和deactivated
- 2022-05-25 Python異常處理如何才能寫得優雅(retrying模塊)_python
- 2022-11-04 C++淺析內存分區模型概念與示例_C 語言
- 2023-12-19 Mybatis使用注解實現復雜動態SQL
- 2024-07-15 Redis底層數據結構-鏈表
- 2022-10-12 Python數據分析matplotlib折線圖案例處理_python
- 2023-04-18 獲取Android簽名MD5的方式實例詳解_Android
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支