Home > Blockchain >  Is it efficient passing structs as parameters by value to a function?
Is it efficient passing structs as parameters by value to a function?

Time:08-26

So far as I know, structs can be passed as parameter by value, or we can also pass it by reference, using pointers.

Is it efficient passing structs by value? If we have big structs with lots of fields, this does not seem to be efficient, since the struct data is copied to the formal parameters of the function, and this involves computational costs.

It seems that, in these cases, passing structs by reference is a better option. Does this make sense?

Another related question is if compilers do optimizations in this sense, converting parameter passing by value to reference.

CodePudding user response:

If a structure is small, pass it by value. Modern calling conventions provide for passing small structures in registers, on suitable platforms.

If a structure is large, you might define your routine to receive the structure by reference (using a pointer to a const-qualified type).

You should also declare the pointer with restrict, as in const struct foo * restrict p. Otherwise, it is possible that passing a structure by reference can impair optimization. Consider passing const struct foo *p to a routine that also has a parameter struct foo *q or float *f. Inside the routine, if the code changes the structure that q points to or the float that f points to, the compiler cannot generally know that q is not pointing to the same structure as p or that f is not pointing to a float that is a member of the structure p points to. This can cause the compiler to reload data from p multiple times when in fact no changes to p are occurring. Using restrict tells the compiler that caller will not pass a p such that data using via p will not also be used inside the routine via other points.

Another related question is if compilers do optimizations in this sense, converting parameter passing by value to reference.

This is not common. However, returning a structure by reference is common. The calling convention is typically that the caller provides a place for the returned structure to be written to and passes a pointer to that, invisibly to the source code.

CodePudding user response:

It will not be efficient for sure, but sometimes we want to work on the local automatic variable. When you change the automatic variable it will stop to exist when the function returns and all changes will be made only to this local variable. If it is passed by a pointer then the function will modify the original object, not the local object. For this reason, the compiler will not optimize it.

typedef struct
{
    double x[10000];
}big_struct;

void __attribute__((noinline)) foo(big_struct bs)
{
    for(size_t i =0; i < sizeof(bs.x) / sizeof(bs.x[0]); i  ) printf("%f\n", bs.x[i]);
}


void bar(void)
{
    big_struct x;

    /* some code */

    foo(x);
}
.LC0:
        .string "%f\n"
foo:
        push    rbp
        push    rbx
        sub     rsp, 8
        lea     rbx, [rsp 32]
        lea     rbp, [rsp 80032]
.L2:
        movsd   xmm0, QWORD PTR [rbx]
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 1
        add     rbx, 8
        call    printf
        cmp     rbx, rbp
        jne     .L2
        add     rsp, 8
        pop     rbx
        pop     rbp
        ret
bar:
        sub     rsp, 160008
        mov     edx, 80000
        lea     rsi, [rsp 80000]
        mov     rdi, rsp
        call    memcpy
        call    foo
        add     rsp, 160008
        ret
  • Related