日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

多参的实现原理

發布時間:2023/12/20 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多参的实现原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

相信大家都使用過C語言的庫函數:printf("%d%d", 1, 2)的吧,使用確實很方便功能也很強大。

但是為什么它可以接受多個參數呢?

現在我們來解析一下多參的實現原理,網上也找了一些文章。發現解析得都不全面。并且有BUG。

先看如下源碼:

#include <windows.h> #include <stdio.h> #include <winnt.h>void MySprintf(char* szBuffer, const char* szFormat, ...) {va_list pa; // 定義一個指針va_start(pa, szFormat); // 把指針賦值為第一個參數的值vsprintf(szBuffer, szFormat, pa);// va_end(pa); // 清空 } int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow) {char szBuffer[128] = {0};MySprintf(szBuffer, "%d%d%d", 1,2,3);return 0 ; }

首先,我們函數壓參順序是重右往左,對應的棧空間內存地址從高到低。

MySprintf(szBuffer, "%d%d%d", 1,2,3);

這行代碼,分別想棧中壓入3, 2, 1, 然后再是szFormat的內存空間,在是szBuffer的內存空間.

內存結構如下:

?

熟悉函數調用的幾步過程,壓入參數,保存返回地址和棧頂,開辟局部變量空間.

現在保存了返回地址,然后繼續執行的話,就是保存棧頂和開辟va_list pa所需的內存空間.

va_list其實也就是char* 類型。占4個字節。繼續執行后如下:

看到了嗎,va_start(pa, szFormat); 這條語句計算出了參數的起始地址,

它是如何計算出的呢?我們既然知道了內存布局, 那szFormat取地址+sizeof(va_list)。

說簡單點也就是:szFormat的內存地址 + 4個字節. 不就剛好偏移到第一個參數的地址處了嗎?

并且, 以上的MySprintf函數等同于下面這種寫法:

void MySprintf(char* szBuffer, const char* szFormat, ...) {char* pCh = NULL;pCh = (char*)&szFormat + sizeof(pCh);vsprintf(szBuffer, szFormat, pCh);pCh = NULL; }

現在,我們得到了參數的內存首地址,但是還缺少信息。缺什么信息?

當前地址處有幾個參數,每個參數什么類型(占用字節數)?

關鍵的地方就在這里了。szFormat中有類型信息信息,并且有類型信息的個數,我們可以通過遍歷字符串,

找出類型信息的順序和個數。然后根據遍歷找到的信息。來解析參數的內存首地址。

具體的做法.在vsprintf中有實現,下面是拷貝vsprintf的實現代碼,

#ifndef _COUNT_int __cdecl vsprintf (char *string,const char *format,va_list ap) #else /* _COUNT_ */int __cdecl _vsnprintf (char *string,size_t count,const char *format,va_list ap) #endif /* _COUNT_ */{FILE str;REG1 FILE *outfile = &str;REG2 int retval;_ASSERTE(string != NULL);_ASSERTE(format != NULL);outfile->_flag = _IOWRT|_IOSTRG;outfile->_ptr = outfile->_base = string; #ifndef _COUNT_outfile->_cnt = MAXSTR; #else /* _COUNT_ */outfile->_cnt = count; #endif /* _COUNT_ *//*簡單說明:關鍵代碼處,大家直接跟進去即可,先是做些判斷,然后設置一些標志位,最后把數字根據設置的標志轉為字符串.*/retval = _output(outfile,format,ap );_putc_lk('\0',outfile);return(retval); }

本人菜鳥,水平有限,望各路大牛指點!

轉載于:https://www.cnblogs.com/ziolo/archive/2013/04/22/3036346.html

總結

以上是生活随笔為你收集整理的多参的实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。