tags:

views:

394

answers:

6

Hello,

gcc 4.4.4 c89

I have always used strncpy to copy strings. I have never really used memmove or memcpy very much. However, I am just wondering when would you decide whether to use strncpy, memmove, or memcpy?

The code I am writing is for a client/server application. In the documentation they use bcopy. However, could I do the same with the others?

bcopy((char*)server->h_addr,
      (char*)&serv_addr.sin_addr.s_addr,
      server->h_length);

Many thanks,

+6  A: 

strcpy (and other str* methods) stop when they encounter a NULL (0) byte. memcpy and related functions to NOT stop when they encounter a NULL byte.

If you have binary data, you must use memcpy. In your example, you are copying binary data, not string data.

strncpy is a special case where it will stop copying at a NULL byte, but still continue to pad the output with NULLs up to the specified length.

Yann Ramin
+1, Fair enough, though one might argue that all data is binary data. ;)
WhirlWind
strncpy doesn't stop filling the target buffer, though. strncpy writes exactly the given number of bytes, either only copying the start of the string if it is too long, or adding zeros to the end of the copy to fill the buffer.
Doug Currie
Thanks, clarified strncpy
Yann Ramin
`memcpy` is also often faster for `'\0'` terminated strings if you happen to already know the length of the string.
nategoose
+3  A: 

Use strncpy() only if you know there's enough space for the string - because it does not guarantee null termination, and is over-enthusiastic if the destination is way shorter than the source string (because it null pads the string to full length). And if you know the length, you can use memmove()...

If you know the lengths of the strings, memmove() is a sensible choice - and nominally faster than strncpy() because it does not have to check for nulls as it goes; it just copies the relevant number of bytes. (I pretend memcpy() doesn't exist as it can fail if the source and destination areas of memory overlap, whereas memmove() will get it right regardless.)

Think of bcopy() as an archaic variant of the mem*() functions.

Jonathan Leffler
There is actually a difference between memcpy(dst,src,size) and memmove(dst,src,size) because memmove "moves" the memory - means: dst and src may overlap whereas overlapping must be avoided when using memcpy.
Robert
I didn't mention `memcpy()` - I pretend it doesn't exist.
Jonathan Leffler
`memcpy()` is cheaper than `memmove()` in most cases, as you usually know that the source and destination buffers don't overlap.
Hasturkun
+3  A: 

If you don't need the buffer-filling behavior of strncpy but want the safety of not overflowing the buffer, consider strlcpy

From wikipedia:

strlcpy offers two features that are designed to help software developers avoid problems. The function takes the size of the destination as a parameter, avoiding buffer overflows if the size parameter is correct. If this size is greater than zero, a nul byte is always written to the destination, so the resulting string is always nul-terminated (even if the source string was truncated to fit).

Doug Currie
+7  A: 

You should never use strncpy (unless you are dealing with that rare specific situation it was introduced for). The function is not intended to be used with zero-terminated C-strings. The name given to that function is just a historical blunder, and happens to be the main source of the confusion for the people who attempt to use it. strncpy is a function introduced to support so-called "fixed width" strings, not zero-terminated strings. Using strncpy with zero-terminated strings is bad programming practice, even though you can whip it into some resemblance of "working" for that purpose.

A function for limited length "safe" string copying does not exist in C library, however some implementations provide it under the name strlcpy, which already became a de-facto standard name for this function. If your implementation does not provide strlcpy, implement it yourself.

Also, it is true that in many cases you can replace str... function with mem... functions, i.e. when you know the exact number of characters to copy.

AndreyT
Sure? IMHO `strncpy` has nothing to do with fixed width strings, the only problem is that `strncpy` does not zero terminate the target string, if the source string is larger than the given size (which is the source of confusion..).
frunsi
@frunsi: Absolutely sure. The history of `strncpy` is well-known and well-documented. There's no room for any "IMHO" here. The function was created to fill 14-character long file name fields in one archaic version of Unix file system. That's the only role it was ever meaningfully used for and that's the only role it is good for.
AndreyT
It has two problems: 1) it doesn't zero terminate if the source is long, 2) it fills with zeros to the end of the buffer is the source is short. Both are obvious and immediate sighs of fixed width strings, of course.
AndreyT
When I use strncpy. I always do the following strncpy(dst_str, src_str, strlen(dst_str) + 1)). This way you could never have a buffer overrun, as you will never copy more than the dst_str can handle. However, the question was when would you decide when to use either of them? Is there some criteria that you would decide on?
robUK
@robUK: Sorry, but this is plain nonsense. What on Earth the length of the current dst string has to do with the number of characters I want to copy? In fact, in 99 cases out of 100 the dst buffer will be uninitialized, so applying `strlen` to it just make no sense whatsoever.
AndreyT
Again, using `strncpy` with zero-terminated strings is like using a hammer to drive in woodscrews. Just because you can do it, does not mean you should.
AndreyT
@Andrey, I should have written sizeof(dst_str) instead of strlen.
robUK
@robUK: It is not enough to "not have buffer overrun". In addition to "not having buffer overrun", we also want to obtain the correct result (a zero-terminated string in dst) and we also want to avoid wasting time doing unnecessary work. `strncpy` doesn't help us with it, in general case. Which is why we don't use `strncpy` for that purpose.
AndreyT
I went down this road a while back and discovered just how bad strncpy is (for how it seems to be used as a 'safer' strcpy). I did not find any historical reason for why it is so bad, but you explanation makes a lot of sense, and I don't hate strncpy so much. It is too bad that strncpy is in the std libs and strlcpy is so not (usually), especially considering I have NEVER seen it used as you have described its intended application.
Dolphin
@AndreyT: well, then thx for bit of history! :-) +1
frunsi
Argh, initially I upvoted your answer, then wanted to revert the upvote but accidentaly I down-voted it. Now I can't upvote it until its edited. Damn... sorry
frunsi
+1 there it is...
frunsi
It it worth pointing out that if you pre-check to see if you are going to be truncating the string (due to insufficient destination space), then you will also know the exact number of characters to copy (so you can use `memcpy` / `memmove`). By the way, one modern use case that I have found for `strncpy` was filling out a fixed-size buffer from a supplied password string, that was to be processed to create an encryption key. `strncpy` was perfect for this (but it is so unusual that I actually put a comment in clarifying that I *really* did want `strncpy`!).
caf
+3  A: 

No one answered all your questions.

strncpy() is used to copy data from a source to a dest of a set size, copying (padding) 0x00s if a 0x00 byte is found in the source array (string) before the end of the buffer. As opposed to strcpy which will blissfully copy forever until a 0 byte is found - even if said byte is well beyond your buffer.

memcpy() is used to copy from source to dest no matter what the source data contains. It also tends to be very hardware optimized and will often read system words (ints/longs) at a time to speed up copying when alignment allows.

memmove() is used to copy from an overlapping source and destination area (say moving an array's contents around within itself or something similiar - hence the move pnumonic.) It copies data starting at the back instead of the front to prevent data loss from the overlapping regions clobbering data before it can be read. It alos tends to be slightly less efficient as there usually isn't much hardware help copying data from back to front.

bcopy() and its relatives (bzero, and a few others) is a byte copy function I've seen now and then in embedded land. Usually, it copies data 1 byte at a time from source to dest to prevent misaligned memory address issues, though any good memcpy will handle this so its use is quite often suspect.

Good luck!

Michael Dorgan
strncpy doesn't terminate the copy early. strncpy writes exactly the given number of bytes, either only copying the start of the string if it is too long, or adding zeros to the end of the copy to fill the buffer.
Doug Currie
Then I learned something new today as well. I thought it terminated early. (browses net...) Lookie there. Changing my explanation above now :)
Michael Dorgan
+1  A: 

If you're looking for a safe/fast way to copy, I've been happy with the following technique:

memcpy( dest, src, sizeof (dest));
dest[sizeof(dest) - 1] = '\0';       // ensure null termination

Less efficient, but also works to limit the bytes written and null-terminate the string:

sprintf( dest, sizeof (dest), "%s", src);

Also returns the number of bytes it would have written, so you can tell if truncation took place.

tomlogic