Function parameters of C (39)

        We talked about the meaning of functions in the previous blog post, so let's talk about function parameters today . Function parameters are essentially the same as local variables and allocate space on the stack. The initial value of function parameters is the actual parameter value when the function is called . Use the following diagram to illustrate practically

picture.png

        The order of evaluation of function parameters depends on the compiler implementation, let's see what is the output of the following code? why?

#include <stdio.h>

int func(int i, int j)
{
    printf("i = %d, j = %d\n", i, j);
    
    return 0;
}

intmain()
{
    int k = 1;
    
    func(k++, k++);
    
    printf("%d\n", k);
    
    return 0;
}

        We theoretically analyze that the func function first performs k++, then i corresponds to 1, and then performs k++ again, corresponding to j is 2. Then line 14 should print i = 1, j = 2,. At this point k is 3, so the value printed on line 16 should be 3. Let's see if the compilation results are as we analyzed, the compilation results are as follows

picture.png

        We see that i and j are the opposite of what we analyzed, so what's going on here? It turns out that in the gcc compiler, the implementation of function parameters is operated from right to left, not from left to right as we thought. Let's compile it again in the BCC compiler and see what the result is?

picture.png

        Then we see that this is also implemented in the BCC compiler. Function parameters are manipulated from right to left. In modern compilers, function parameters are basically manipulated in right-to-left order. In some ancient compilers, there is also a left-to-right implementation, and the implementation of this depends on the implementation of the specific compiler.

        Let's talk about a knowledge point in C language: sequence point! Then there is a certain sequence point in the program. The sequence point refers to the latest time when the variable value is modified during the execution process. When the program reaches the sequence point, all the operations done before must be completed . So where are the sequence points in C at those moments? a> At the end of each complete expression, that is, at the semicolon; b> &&, ||, ?: and after each parameter of the comma expression is evaluated; c> After the evaluation of all actual parameters in the function call is completed (that is, enter function) ;

        Let's take the code as an example for analysis, the code is as follows

#include <stdio.h>

intmain()
{
    int k = 2;
    int a = 1;
    
    k = k++ + k++;
    
    printf("k = %d\n", k);
    
    if( a-- && a )
    {
        printf("a = %d\n", a);
    }
    
    return 0;
}

        We see that the addition of k++ is performed twice in line 8, and our analysis result should be 5; a-- in line 12 is executed, and a is 0, but at this time, the condition is still true after it is combined with a, So line 14 should print a = 0; shall I see the result?

picture.png

        Then we see that the first one we analyzed is correct, but a = 0 is not printed, let's see what the BCC compiler is

picture.png

        We see that k = 6, a = 0 is still not printed. Let's take a look at the VS compiler again

picture.png

        Let's go into the disassembly to see how it executes

picture.png

        We see that it is executed like this. First, the addition operation is performed. At this time, the ++ operation is suspended, and the program sees it; only then does it realize that the sequence point is reached, so the two ++ operations are executed, so the last k is 6. Let's take a look at how line 14 is executed

picture.png

        We see that it is after executing a-- and seeing the && operation, we realize that the sequence point is reached, and we return. Then the value of a has become 0 at this time, and the condition of the if statement is false at this time, so the print statement in it will not be executed.

        Next, let's take a look at the order in which the parameters are pushed onto the stack. The calculation order of function parameters depends on the compiler implementation. So how is the stacking order of function parameters determined? This piece involves a concept: the calling convention . When a function call occurs: a> the parameters are passed to the called function; b> the return value is returned to the function caller ; the calling convention describes how the parameters are passed to the stack and how the stack is maintained, the order in which the parameters are passed, the calling stack cleanup.

        The calling convention is a predefined and understandable calling protocol, and the calling convention is usually used for library calls and library development. Let's take a look at some commonly used operations: a> push the stack from right to left: __stfcall, __cdecl, __thiscall; b> push the stack from left to right: __pascall, __fastcall; then our general C program development follows the above __cdecl this way.

        So if we want to write a function that calculates the average, we must first think of the following

#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;
}

intmain()
{
    int array[] = {1, 2, 3, 4, 5};
    
    printf("%f\n", average(array, 5));
    
    return 0;
}

        We use an array to complete this function, then we have to define an array. Is there any way we can accomplish this function without defining an array? The answer is that we can use variadic functions to achieve this function. Variable-parameter functions can be defined in C language, and the implementation of variable-parameter functions depends on the stdarg.h header file . We have to introduce several concepts : a> va_list -- parameter set; b> va_arg -- take specific parameter values; c> va_start -- identify the start of parameter access; d> va_end -- identify the end of parameter access ;

        Let's take a look at how the variable parameter version of the program is implemented. The code is as follows

#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;
}

intmain()
{
    printf("%f\n", average(5, 1, 2, 3, 4, 5));
    printf("%f\n", average(4, 1, 2, 3, 4));
    
    return 0;
}

        We define the args parameter on line 6, start on line 10, add the arguments on line 14, and end on line 17. Let's see if such a definition on lines 24 and 25 works? Let's see the compilation result

picture.png

        The result has been implemented correctly, isn't it very convenient? We can define its size and content at any time. Then there are also restrictions on variadic parameters: a> variadic parameters must be accessed one by one from the beginning to the end; b> there must be at least one definite named parameter in the parameter list; c> variadic function cannot determine the actual number of parameters, It is also impossible to determine the actual type of the parameter, we can only specify it manually; Note: If the wrong type is specified in va_arg, the result is unpredictable!

        Through the study of function parameters, the summary is as follows: 1. The parameters of the function are allocated space on the stack; 2. There is no fixed calculation order for the actual parameters of the function; 3. The sequence point is the latest time for variable modification in the C language; 4. , The calling convention specifies the stacking order of function parameters and the stack cleaning method; 5. The variable parameter function provides a function design skill and provides a more convenient function calling method; 6. Variable parameters must be in order access, cannot directly access the intermediate parameter value.


        Welcome to learn C language together, you can add me QQ: 243343083 .

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325167373&siteId=291194637