Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a performance difference between an int and a struct containing only an int?

In C, a typedef doesn't grant you any additional type safety. You can use the the new type any place you can use the old type. Sometimes that's what I want, and sometimes it is not. Sometimes I want the compiler to warn me if I misuse my new type.

To make that happen, I sometimes do something like this:

typedef struct {
    int value;
} NewType;

NewType doSomethingNT(NewType a, NewType b) {
    return a.value + b.value;
}

Compared to:

int doSomethingI(int a, int b) {
    return a + b;
}

(That plus is just an example. Let's assume that either there's a function call overhead in both cases, or else I ask the function to be inlined in both cases. But let's not compare doSomethingNT to the bare + operator, obviously the latter is faster because it doesn't have the function call overhead)

I guess I'm asking, is there any overhead in "boxing" a primitive type a one element struct, but using that struct as a value type. (I.e. I'm not calling malloc and using pointers to it like how boxing works in Java.)

like image 305
Tim Avatar asked Mar 06 '14 19:03

Tim


People also ask

Which is faster struct or class in C++?

On runtime level there is no difference between structs and classes in C++ at all. So it doesn't make any performance difference whether you use struct A or class A in your code.

Does structure bring additional overhead to a program justify?

No. Struct does not add any size, or have any overhead in the compiled C. It is a layer of syntax that requires additional work by the compiler, but has no overhead at runtime.


1 Answers

I tried this with the clang (specifically Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)) at -O2.

The source:

#include <stdio.h>

struct da_int {
    short i;
};

struct da_int add(struct da_int x, struct da_int y) {
    struct da_int rv = {x.i + y.i};
    return rv;
}

int main(int argc, char *argv[]) {
    struct da_int x = {5}, y = {3};
    printf("%d\n", add(x, y).i);
}

The compiler foiled my plan slightly—the generated main never calls add, instead computing the result at compile-time:

_main:                                  ## @main
    .cfi_startproc
## BB#0:
    pushq    %rbp
Ltmp7:
    .cfi_def_cfa_offset 16
Ltmp8:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp9:
    .cfi_def_cfa_register %rbp
    leaq    L_.str(%rip), %rdi
    movl    $8, %esi
    xorb    %al, %al
    callq    _printf
    xorl    %eax, %eax
    popq    %rbp
    ret
    .cfi_endproc

It did generate an add function though! It takes its arguments in registers and returns a result in a register. The wrapper struct disappears completely in the compiler output, at least for this trivial case:

_add:                                   ## @add
    .cfi_startproc
## BB#0:
    pushq    %rbp
Ltmp2:
    .cfi_def_cfa_offset 16
Ltmp3:
    .cfi_offset %rbp, -16
    movq    %rsp, %rbp
Ltmp4:
    .cfi_def_cfa_register %rbp
    addl    %esi, %edi
    movw    %di, %ax
    popq    %rbp
    ret
    .cfi_endproc

Given that, I wouldn't worry too much about extra overhead from doing this.

like image 128
LnxPrgr3 Avatar answered Oct 04 '22 18:10

LnxPrgr3