Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

history of memcpy and memset vs assignment and initialization

Tags:

c

So, my understanding is that the following code:

somestruct_t a = {0};
somestruct_t b;
b = a;

is always preferable, when possible, to:

somestruct_t a;
somestruct_t b;
memset(&a, 0, sizeof(a));
memcpy(&b, &a, sizeof(a));

And the top constructs are almost always possible...which leads me to my question: Since the top code both performs well, and is to me clearly more intuitive to someone learning the language, why are the memset and memcpy patterns so amazingly prevalent in C and even non-OO C++ code? Literally every project I've worked on for decades prefers the bottom pattern.

I'm assuming there is some historical reason for it, such as very old compilers not supporting it or somesuch, but I'd very much like to know the specific reason.

I know general history questions are off-topic, but this is about a very specific bad practice that I would like to understand better.

EDIT I am NOT trying to assert that memcpy and memset are bad in general. I'm talking about a very specific use pattern of assignment or initialization of a single structure.

like image 731
zzxyz Avatar asked Mar 06 '23 19:03

zzxyz


1 Answers

It sounds like your experience is significantly different from mine, and from several of the other commentators here.

I don't know anyone who prefers

memcpy(&a, &b, sizeof(a));

over

a = b;

In my programming world (and in just about any world I can imagine), simple assignment is vastly preferable to memcpy. memcpy is for moving chunks of arbitrary data around (analogous to strcpy, but when it's arbitrary bytes instead of null-terminated strings). It's hard to imagine why anyone would advocate using memcpy instead of struct assignment. Naturally there are individual programmers everywhere who have gotten into various bad habits, so I guess I can't be too surprised if there are some who prefer the opposite, but I have to say, I would generally disagree with what they're doing.

Someone speculated in the comments that there was perhaps some historical precedent at work, but at least for the memcpy-versus-assignment questions, I can state with some certainty that this is not the case.

Once upon a time, before there was C90 memcpy, there was BSD bcopy, but before there was bcopy there wasn't a standard function for doing an efficient copy of a bunch of bytes from point a to point b. But there was struct assignment, which really has been in the language almost from the beginning. And struct assignment typically uses a nice, tight, compiler-generated byte-copying loop. So there was a time when it was fashionable to do something like this:

#define bcpy(a, b, n) (*(struct {char x[n];} *)a = *(struct {char x[n];} *)b)

I may have gotten the syntax wrong, but this hijacks the compiler's ability to do efficient struct assignment, and repurposes it to copy n bytes from arbitrary pointer b to arbitrary pointer a, i.e. just like bcopy or memcpy.

In other words, it's not like memcpy came first, followed by struct assignment -- it was actually exactly the opposite!

Now, memset versus struct initialization is a different story.

Most of the "clean" ways of zeroing a struct are initializations, but of course it's not uncommon to want to set a struct to all zero at some point later than when it was defined. It's also not uncommon to have a dynamically-allocated struct, and using malloc/realloc rather than calloc. So in those cases, memset is attractive. I think modern C has struct constants you can use at any time, but I'm guessing I'm not the only one who still hasn't learned them and so is still tending to use memset instead.

So I wouldn't consider using memset to be poor style, not in the same way as memcpy is poor style for struct assignment.

Although I have seen, and written, code that did something like

struct s zerostruct = { 0 };

and then later

a = zerostruct;

as a "better style" alternative to

memset(&a, 0, sizeof(a));   

Bottom line: I wouldn't agree that memcpy is recommended over struct assignment, and I am critical of anyone who prefers it. But memset is quite useful (and not disrecommended) for zeroing structures, because the alternatives aren't nearly as compelling.

like image 190
Steve Summit Avatar answered Mar 10 '23 12:03

Steve Summit