2

I want to copy data from different variables and put it together in an array so that I can process it further.

I have studied direct assignment and memcpy method and think memcpy is used to copy complete buffer and not individual elements. Also I think it may take time and waste CPU cycles to use memcpy for individual bytes.

Can you please let me know from below example what should be used in such case since it is running in multithreaded environment(different example) and varibles may change?

#include <stdio.h>
#include <stdint.h>

int main()
{

    printf("Direct assign method\n");

    uint8_t pack_id = 123;
    uint8_t pack_age = 76;
    uint8_t pack_cmd = 30;

    uint8_t cus_data[3] = {0};

    cus_data[0] = pack_id;
    cus_data[1] = pack_age;
    cus_data[2] = pack_cmd;

    printf("Memcpy method\n");

    pack_id = 112;
    pack_age = 89;
    pack_cmd = 25;

    memcpy(&cus_data[0], &pack_id, sizeof(pack_id));
    memcpy(&cus_data[1], &pack_age, sizeof(pack_age));
    memcpy(&cus_data[2], &pack_cmd, sizeof(pack_cmd));

    return 0;
}
9
  • 5
    Using memcpy for one byte would probably take more time than direct assignment. Commented Dec 18, 2019 at 14:31
  • 6
    Choose the best readable version and leave the compiler to do the optimization. memcpy() looks inappropriate here, indeed. Commented Dec 18, 2019 at 14:33
  • 1
    Modern compilers are likely to change the memcpy into an assignment. If you can read assembly code, put this code into godbolt.org , or you can even just skim the assembly code and see that it doesn't call memcpy. Commented Dec 18, 2019 at 14:44
  • 2
    The premise of the question is wrong. If these variables change in a multithreaded program while doing the assignment then you have a data race and the behaviour of the program is undefined. Commented Dec 18, 2019 at 14:44
  • 1
    @FiddlingBits memcpy is a standard library function and the compiler is allowed to optimize as it pleases. Commented Dec 18, 2019 at 14:46

3 Answers 3

7

cus_data[0] = pack_id; is never slower than memcpy(&cus_data[0], &pack_id, sizeof(pack_id));. They may however be equally fast, if the compiler inlines the memcpy call, which is very likely.

What you should do instead of worrying about micro-optimizations is to write the most readable code possible. Worry about optimizations when you encounter actual performance problems.

Since cus_data[0] = pack_id; is the most readable, that's what you should be doing.


in such case since it is running in multithreaded environment

Doesn't make a difference. Either you need to protect the variables against re-entrancy bugs, or you don't need to protect them. This has nothing to do with simple assignment vs memcpy, because neither of them are guaranteed to be atomic.

It doesn't matter how small/large the variables are, since nothing in the C language guarantees atomic access unless you use C11 _Atomic and similar.

Sign up to request clarification or add additional context in comments.

Comments

4

Practically every optimizing compiler (certainly gcc, clang, and icc) treats memcpy (and a handful of other libc functions, e.g., memcmp) as a builtin that's backed up by a real libc function of the same name.

Compilers will generally only call the real function iff doing the work with inline assembly looks like too much work.

Copying a character certainly doesn't fall in that category. These two generate the same assembly with gcc/clang/icc:

#include <string.h> //compilers generally know about memcpy
//but C still requires that it should be prototyped

void assign_char(char *X)
{
    *X = 'x';
}

void memcpy_char(char *X)
{
    memcpy(X,"x",1);
}

x86_64 output:

 assign_char:
        mov     BYTE PTR [rdi], 120
        ret
 memcpy_char:
        mov     BYTE PTR [rdi], 120
        ret

It doesn't matter which one you use. The memcpy version is more generic (works on arrays too, even though arrays can't be assigned to/from in C) and allows you to circumvent strict aliasing, but it's also a bit more verbose to write.

Comments

-1

The most of modern computer's size of address is 8 bytes which 64bit. You just do not assign a address which 8bytes into 1byte(8bit) storage variable.

for example memcpy(&cus_data[0], &pack_id, sizeof(uinit8_t*));

However, you did this below 3 times, for a sequence. memcpy(&cus_data[0], &pack_id, sizeof(uinit8_t));

memcpy() func. is such as this

void memcpy(void *dest, void *src, size_t size) { 
char *c_src = (char *)src; 
char *c_dest = (char *)dest; 
for (int i=0; i<size; i++) 
    c_dest[i] = c_src[i]; 

}

It will copy src to dest 1byte by 1byte. and so on..

so, I like to use struct, case 1 instead of above further case 2 code copy a pointer once.

struct PACK{
uint8_t id;
uint8_t age;
uint8_t cmd;

};

int main() {

struct PACK pack = { .id = 123, .age = 76, .cmd = 30 };
uint8_t cus_data[3];

// case 1
memcpy(cus_data, &pack, 3);

// case 2
uint8_t *p = (uint8_t*)&pack;


for(int i=0; i<3; i++)
    printf("%d\n", p[i]);
return 0;

}

1 Comment

What has this to do with the question? Nobody is trying to write an addess into 1 byte anywhere.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.