Search code examples
objective-ccarraysvariable-assignmentmemcpy

Assignment or memcpy? What is the preferred approach to setting an array member variable?


For this example, I am working with objective-c, but answers from the broader C/C++ community are welcome.

@interface BSWidget : NSObject {
    float tre[3];
}
@property(assign) float* tre;

.

- (void)assignToTre:(float*)triplet {
    tre[0] = triplet[0];
    tre[1] = triplet[1];
    tre[2] = triplet[2];
}

.

- (void)copyToTre:(float*)triplet {
    memcpy(tre, triplet, sizeof(tre) );
}

So between these two approaches, and considering the fact that these setter functions will only generally handle dimensions of 2,3, or 4...

What would be the most efficient approach for this situation?

Will gcc generally reduce these to the same basic operations?

Thanks.


Solution

  • A quick test seems to show that the compiler, when optimising, replaces the memcpy call with the instructions to perform the assignment.

    Disassemble the following code, when compiled unoptimised and with -O2, shows that in the optimised case the testMemcpy function does not contain a call to memcpy.

    struct test src = { .a=1, .b='x' };
    
    void testMemcpy(void)
    {
      struct test *dest = malloc(sizeof(struct test));
      memcpy(dest, &src, sizeof(struct test));
    }
    
    void testAssign(void)
    {
      struct test *dest = malloc(sizeof(struct test));
      *dest = src;
    }
    

    Unoptimised testMemcpy, with a memcpy call as expected

    (gdb) disassemble testMemcpy 
    Dump of assembler code for function testMemcpy:
       0x08048414 <+0>: push   %ebp
       0x08048415 <+1>: mov    %esp,%ebp
       0x08048417 <+3>: sub    $0x28,%esp
       0x0804841a <+6>: movl   $0x8,(%esp)
       0x08048421 <+13>:    call   0x8048350 <malloc@plt>
       0x08048426 <+18>:    mov    %eax,-0xc(%ebp)
       0x08048429 <+21>:    movl   $0x8,0x8(%esp)
       0x08048431 <+29>:    movl   $0x804a018,0x4(%esp)
       0x08048439 <+37>:    mov    -0xc(%ebp),%eax
       0x0804843c <+40>:    mov    %eax,(%esp)
       0x0804843f <+43>:    call   0x8048340 <memcpy@plt>
       0x08048444 <+48>:    leave  
       0x08048445 <+49>:    ret 
    

    Optimised testAssign

    (gdb) disassemble testAssign 
    Dump of assembler code for function testAssign:
       0x080483f0 <+0>: push   %ebp
       0x080483f1 <+1>: mov    %esp,%ebp
       0x080483f3 <+3>: sub    $0x18,%esp
       0x080483f6 <+6>: movl   $0x8,(%esp)
       0x080483fd <+13>:    call   0x804831c <malloc@plt>
       0x08048402 <+18>:    mov    0x804a014,%edx
       0x08048408 <+24>:    mov    0x804a018,%ecx
       0x0804840e <+30>:    mov    %edx,(%eax)
       0x08048410 <+32>:    mov    %ecx,0x4(%eax)
       0x08048413 <+35>:    leave  
       0x08048414 <+36>:    ret   
    

    Optimised testMemcpy does not contain a memcpy call

    (gdb) disassemble testMemcpy 
    Dump of assembler code for function testMemcpy:
       0x08048420 <+0>: push   %ebp
       0x08048421 <+1>: mov    %esp,%ebp
       0x08048423 <+3>: sub    $0x18,%esp
       0x08048426 <+6>: movl   $0x8,(%esp)
       0x0804842d <+13>:    call   0x804831c <malloc@plt>
       0x08048432 <+18>:    mov    0x804a014,%edx
       0x08048438 <+24>:    mov    0x804a018,%ecx
       0x0804843e <+30>:    mov    %edx,(%eax)
       0x08048440 <+32>:    mov    %ecx,0x4(%eax)
       0x08048443 <+35>:    leave  
       0x08048444 <+36>:    ret