色偷偷偷久久伊人大杳蕉,色爽交视频免费观看,欧美扒开腿做爽爽爽a片,欧美孕交alscan巨交xxx,日日碰狠狠躁久久躁蜜桃

x
x

C語言的那些小秘密之變參函數(shù)的實現(xiàn)

發(fā)布時間:2016-2-19 09:08    發(fā)布者:designapp
關(guān)鍵詞: C語言 , 函數(shù)
在學習C語言的過程中我們可能很少會去寫變參函數(shù),印象中大學老師好像也沒有提及過,但我發(fā)現(xiàn)變參函數(shù)的實現(xiàn)很巧妙,所以還是特地在此分析下變參函數(shù)的實現(xiàn)原理。無需標準C的支持,我們自己寫代碼來實現(xiàn)。
先來看看一個實現(xiàn)代碼:
#include
#define va_list void*
#define va_arg(arg, type) *(type*)arg; arg = (char*)arg + sizeof(type);
#define va_start(arg, start) arg = (va_list)(((char*)&(start)) + sizeof(start))
int sum(int nr, ...)
{
int i = 0;
int result = 0;
va_list arg = NULL;
va_start(arg, nr);
for(i = 0; i


#define va_list void*通過這句代碼我們實現(xiàn)了定義va_list是一個指針,參數(shù)類型不定,它可以指向任意類型的指針。為了讓arg指向第一個可變參數(shù),我們用nr的地址加上nr的數(shù)據(jù)類型大小就行了,采用如下的定義可以實現(xiàn)。
#define va_start(arg, start) arg = (va_list)(((char*)&(start)) + sizeof(start)) 。
通過(((char*)&(start)) + sizeof(start)) 可以得到第一個可變參數(shù)的地址,再將其強制轉(zhuǎn)換為va_list類型。
成功取出了第一個可變參數(shù)后,接下來的任務(wù)就是繼續(xù)取出可變參數(shù),方法跟上面求第一個可變參數(shù)的方法一樣,通過arg = (char*)arg + sizeof(type);來實現(xiàn)讓arg指向下一個可變參數(shù),type為可變參數(shù)的類型,通過這種方法可以一一取出可變參數(shù)。
在這里順便給出上面實現(xiàn)代碼的匯編代碼,有興趣的可以讀讀,加深下對于底層匯編代碼的閱讀能力。
.file "varargs.c"
.text
.globl sum
.type sum, @function
sum:
pushl %ebp
movl %esp, %ebp
subl $16, %esp
movl $0, -4(%ebp)
movl $0, -8(%ebp)
movl $0, -12(%ebp)
leal 12(%ebp), %eax
movl %eax, -12(%ebp)
movl $0, -4(%ebp)
jmp .L2
.L3:
movl -12(%ebp), %eax
movl (%eax), %eax
addl %eax, -8(%ebp)
addl $4, -12(%ebp)
addl $1, -4(%ebp)
.L2:
movl 8(%ebp), %eax
cmpl %eax, -4(%ebp)
jl .L3
movl -8(%ebp), %eax
leave
ret
.size sum, .-sum
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $100, 16(%esp)
movl $100, 12(%esp)
movl $100, 8(%esp)
movl $100, 4(%esp)
movl $4, (%esp)
call sum
movl $.LC0, %edx
movl %eax, 4(%esp)
movl %edx, (%esp)
call printf
movl $200, 12(%esp)
movl $200, 8(%esp)
movl $200, 4(%esp)
movl $3, (%esp)
call sum
movl $.LC0, %edx
movl %eax, 4(%esp)
movl %edx, (%esp)
call printf
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2"
.section .note.GNU-stack,"",@progbits樹莓派文章專題:樹莓派是什么?你不知道樹莓派的知識和應(yīng)用
                                
               
其中有幾條指令在此講解下。
leave指令所做的操作相當于如下兩條指令:
movl %ebp, %esp
popl %ebp
ret指令所做的操作相當于如下指令:
pop %eip
如果有對AT&T匯編語法規(guī)則不懂的,可以看看我前面寫的那篇文章。
到這兒為止是乎應(yīng)該是說結(jié)束的時候了,但是細心的讀者可能發(fā)現(xiàn)了一個問題,就是我們在最初給出的代碼部分有一句紅色標記的代碼,如下:
#define va_start(arg, start) arg = (va_list)(((char*)&(start)) + sizeof(start))
為什么要把這句代碼單獨拿出來講解呢,肯定是有原因的,因為((char*)&(start)) +sizeof(start)這句代碼的特殊性在于使用了(char*)進行強制轉(zhuǎn)換,在這里為什么不使用(int*)進行強制轉(zhuǎn)換呢,如改為如下代碼:
#include
#include
#define va_list void*
#define va_arg(arg, type) *(type*)arg; arg = (char*)arg + sizeof(type);
#define va_start(arg, start) arg = (va_list)(((int*)&(start)) + sizeof(start)) //修改為(int*)
int sum(int nr, ...)
{
int i = 0;
int result = 0;
va_list arg = NULL;
va_start(arg, nr);
for(i = 0; i


顯然運行結(jié)果是錯誤的,為什么會出現(xiàn)這樣的錯誤呢,我們暫且不分析,先來看看我們接下來做的修改:
#include
#include
#define va_list void*
#define va_arg(arg, type) *(type*)arg; arg = (char*)arg + sizeof(type);
#define va_start(arg, start) arg = (va_list)(((int*)&(start)) + sizeof(start)/4) //注意對比紅色部分的變化
int sum(int nr, ...)
{
int i = 0;
int result = 0;
va_list arg = NULL;
va_start(arg, nr);
for(i = 0; i


運行結(jié)果正確。
現(xiàn)在來分析下為什么會出現(xiàn)這兩種結(jié)果呢,看看下面我給出的這個圖解和代碼應(yīng)該就能夠很清楚的理解為什么會出現(xiàn)以上的兩種運行結(jié)果了。


代碼如下:
#include
int main()
{
int a = 12;
int *p_int = &a;
char *p_char = (char*)&a;
printf( "%d \t", sizeof(char));
printf( "%d \t", sizeof(int));
printf( "%d \t", p_int+1);
printf( "%d \t", p_char+1);
return 0;
}
運行結(jié)果為:


修改以上紅色部分的代碼,得到如下代碼:
#include
int main()
{
int a = 12;
int *p_int = &a;
char *p_char = (char*)&a;
printf( "%d \t", sizeof(char));
printf( "%d \t", sizeof(int));
printf( "%d \t", p_int+1);
printf( "%d \t", p_char+4);
return 0;
}
注意對比前后代碼的變化部分!!!
運行結(jié)果如下:


首先看看給出的圖,int指針所指向的單元占有四個字節(jié)的空間,而char指針所指向的單元只占有一個字節(jié)的空間。所以如果是整形指針想要取下一個參數(shù),只需加1,但是如果是char指針,如果當前參數(shù)是int型,那么想要取下一個參數(shù)就要加4才能實現(xiàn)。但是值得注意的是,int*和char*所占的存儲單元都是4個字節(jié),這是由我們所使用的32位計算機本身確定的。為了加深大家的印象,特地給出如下代碼:
#include
int main()
{
int a = 12;
int *p_int = &a;
char *p_char = (char*)&a;
printf( "%d \t", sizeof(char*));
printf( "%d \t", sizeof(int*));
return 0;
}
運行結(jié)果如下:


到此為止就是真的該結(jié)束了,總不能沒完沒了的講下去吧,呵呵……
很多代碼僅僅是修改了一點,我都貼出了完整的代碼,是希望你在閱讀的過程中能直接copy過去,看看運行效果,加深下印象。還是那句話,C語言博大精深,我還是C語言菜鳥,以上內(nèi)容難免有錯。
本文地址:http://www.54549.cn/thread-160943-1-1.html     【打印本頁】

本站部分文章為轉(zhuǎn)載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點和對其真實性負責;文章版權(quán)歸原作者及原出處所有,如涉及作品內(nèi)容、版權(quán)和其它問題,我們將根據(jù)著作權(quán)人的要求,第一時間更正或刪除。
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復 返回頂部 返回列表