Author: Chen Xi
Date: 12:20:17
Environment: [Mac 10.7.1 lion intel I3 supports 64-bit gcc4.2.1 xcode4.2]
Reprinted please indicate the source
Q1: What are the essential reasons why function calls with variable parameters can be correctly executed?
A: An important feature of a variable parameter is that the number of parameters is uncertain, but it can be correctly executed. Generally, the stack and the deterministic support of parameter types are required. If neither of the parameter types is certain or within a certain range, variable parameter functions cannot be implemented.
Q2: A Variable Parameter example.
A: For example, calculate the average number of an integer:
Get_average (2,100,100 0), the first parameter indicates that the number of integers for the average is 2, followed by 2 integers 100 and 1000;
To calculate the average of three numbers, call the following method:
Get_average (2,100,100 0, 200 ).
The Code is as follows:
#include <stdio.h>#include <string.h>#include <stdlib.h>#include <stdarg.h>#define PRINT_D(longValue) printf(#longValue" is %ld\n", ((long)longValue));#define PRINT_STR(str) printf(#str" is %s\n", (str));#define PRINT_DBL(doubleValue) printf(#doubleValue" is %f\n", (doubleValue));double get_average(int int_num_count, ...){ va_list list; double sum = 0; int int_num_count_bak = int_num_count; va_start(list, int_num_count); while(int_num_count > 0) { sum += va_arg(list, int); --int_num_count; } va_end(list); return sum / int_num_count_bak;}int main(){ double ret = get_average(2, 3, 4); PRINT_DBL(ret) ret = get_average(3, 3, 4, 5); PRINT_DBL(ret) return 0;}
Q3: The final prototype of the get_average function... is variable parameter?
A: Yes. You can also refer to the prototype of the printf function:
int printf(const char * __restrict, ...) __DARWIN_LDBL_COMPAT(printf) __printflike(1, 2);
Q4: va_list, va_start, va_arg, and va_end. What are their implementations?
A: They are used to obtain the first addresses of parameters from the stack, get the addresses of different parameters in sequence, and end the processing.
Q5: How are several types of functions (or macros) such as va_list implemented internally?
A: In Mac, they are defined as another type by macros, and the specific internal implementation is not made public. The following describes the implementation of Windows (some code ):
#ifndef _VA_LIST_DEFINED#ifdef _M_ALPHAtypedef struct { char *a0; /* pointer to first homed integer argument */ int offset; /* byte offset of next parameter */} va_list;#elsetypedef char * va_list;#endif#define _VA_LIST_DEFINED#endif#ifdef _M_IX86#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )#define va_end(ap) ( ap = (va_list)0 )#elif defined(_M_MRX000)
As you can see, va_list is a structure similar to char *, saving the first address of the parameter (may also include the offset of the next parameter) information;
Va_start locates the address of the first variable parameter;
Va_arg obtains the value of this parameter based on the parameter type;
Va_end performs a simple null setting operation as a flag.
Q6: the default call method of C language functions uses _ cdecl. Does it indirectly support the implementation of variable parameters?
A: Yes. For example, on the ARM platform, when the number of parameters is small, the parameters are preferentially transmitted into registers. If the number of parameters exceeds a certain number, the parameters are imported into the stack. So, do the above Code use registers or stacks on the ARM platform? Create an iOS project in xcode, add the above Code, and compile its arm assembly:
0x0009276c <get_average+0>:subsp, #120x0009276e <get_average+2>:push{r4, r7, lr}0x00092770 <get_average+4>:addr7, sp, #40x00092772 <get_average+6>:subsp, #280x00092774 <get_average+8>:movr4, sp0x00092776 <get_average+10>:bic.wr4, r4, #7; 0x70x0009277a <get_average+14>:movsp, r40x0009277c <get_average+16>:strr3, [r7, #16]0x0009277e <get_average+18>:strr2, [r7, #12]0x00092780 <get_average+20>:strr1, [r7, #8]0x00092782 <get_average+22>:addr1, sp, #200x00092784 <get_average+24>:movsr2, #00x00092786 <get_average+26>:movtr2, #0; 0x00x0009278a <get_average+30>:vldrd16, [pc, #104]; 0x927f6 <get_average+138>0x0009278e <get_average+34>:strr0, [sp, #24]0x00092790 <get_average+36>:vstrd16, [sp, #8]0x00092794 <get_average+40>:ldrr0, [sp, #24]0x00092796 <get_average+42>:strr0, [sp, #4]0x00092798 <get_average+44>:add.wr0, r7, #8; 0x80x0009279c <get_average+48>:strr0, [r1, #0]0x0009279e <get_average+50>:strr2, [sp, #0]0x000927a0 <get_average+52>:movsr0, #00x000927a2 <get_average+54>:movtr0, #0; 0x00x000927a6 <get_average+58>:ldrr1, [sp, #24]0x000927a8 <get_average+60>:cmpr1, r00x000927aa <get_average+62>:ble.n0x927d2 <get_average+102>0x000927ac <get_average+64>:ldrr0, [sp, #20]0x000927ae <get_average+66>:addsr1, r0, #40x000927b0 <get_average+68>:strr1, [sp, #20]0x000927b2 <get_average+70>:ldrr0, [r0, #0]0x000927b4 <get_average+72>:fmsrs0, r00x000927b8 <get_average+76>:fsitodd16, s00x000927bc <get_average+80>:vldrd17, [sp, #8]0x000927c0 <get_average+84>:fadddd16, d17, d160x000927c4 <get_average+88>:vstrd16, [sp, #8]0x000927c8 <get_average+92>:ldrr0, [sp, #24]0x000927ca <get_average+94>:add.wr0, r0, #4294967295; 0xffffffff0x000927ce <get_average+98>:strr0, [sp, #24]0x000927d0 <get_average+100>:b.n0x927a0 <get_average+52>0x000927d2 <get_average+102>:vldrd16, [sp, #8]0x000927d6 <get_average+106>:fldss0, [sp, #4]0x000927da <get_average+110>:fsitodd17, s00x000927de <get_average+114>:fdivdd16, d16, d170x000927e2 <get_average+118>:vmovr0, r1, d160x000927e6 <get_average+122>:subsr4, r7, #40x000927e8 <get_average+124>:movsp, r40x000927ea <get_average+126>:ldmia.wsp!, {r4, r7, lr}0x000927ee <get_average+130>:addsp, #120x000927f0 <get_average+132>:bxlr0x000927f2 <get_average+134>:nop0x000927f4 <get_average+136>:lslsr0, r0, #00x000927f6 <get_average+138>:lslsr0, r0, #00x000927f8 <get_average+140>:lslsr0, r0, #00x000927fa <get_average+142>:lslsr0, r0, #0
Here, we can see that the stack register SP is used and the parameter operation is obtained from the memory related to the sp. You can confirm that the parameter is still transferred using the stack method.
Some seemingly dynamic things are implemented using relatively static things in the C language.
Author: Chen Xi
Date: 12:20:17
Environment: [Mac 10.7.1 lion intel I3 supports 64-bit gcc4.2.1 xcode4.2]
Reprinted please indicate the source