Destination or memcpy? What is the preferred approach for setting an array member variable?

In this example, I am working with objective-c, but responses from the wider 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) ); } 

Thus, between these two approaches and taking into account the fact that these setter functions will mainly handle sizes 2,3 or 4 ...

What would be the most effective approach for this situation?

Will gcc usually reduce them to the same basic operations?

Thanks.

+6
source share
3 answers

A quick test shows that the compiler, when optimizing, replaces the memcpy call with instructions to complete the task.

Parse the following code if it is not optimized and with -O2, shows that in the optimized case the testMemcpy function does not contain a memcpy call.

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

Unoptimized testMemcpy waiting for memcpy call

 (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 

Optimized 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 

Optimized testMemcpy does not contain 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 
+7
source

Speaking from background C, I recommend using direct assignment. This version of the code is more obvious with respect to your intentions and less error prone if your array changes in the future and adds additional indexes that your function does not need to copy.

These two are not strictly equivalent. memcpy usually implemented as a loop that copies data into chunks of a fixed size (which may be less than a float ), so the compiler probably won't generate the same code for the memcpy case. The only way to know for sure is to build it in both directions and look at the emitted assembly in the debugger.

Even if the memcpy call is memcpy , this is likely to lead to more code and slower execution time. The direct assignment case should be more efficient (if your target platform does not require special code to handle float data types). However, this is just an educated guess; the only way to know for sure is to try in both directions and profile the code.

+2
source

memcpy :

  • Prolog function.
  • Initialize the counter and pointers.
  • Check if there are bytes for copying.
  • Copy memory.
  • Increment pointer.
  • Increment pointer.
  • Increment counter.
  • Repeat 3-7 3 or 11 times.
  • Perform the epilog function.

Direct appointment:

  • Copy memory.
  • Copy memory.
  • Copy memory.

As you can see, direct assignment is much faster.

0
source

Source: https://habr.com/ru/post/895353/


All Articles