How to strcpy and return number of copied characters?
Asked Answered
L

5

9

I want to copy a null-terminated string to another location and want to know how long the copied string was. Efficiency is of utmost importance. There ist the strcpy function which can achieve this, but it does not return how many characters are actually copied.

Of course, I could find this out by simply calling strlen afterwards to detect the length of the copied string, but this would mean traversing the characters in the string again a second time, although strcpy has to track how many characters it copies anyway. For performance reasons, I do not want such a second traversal.

I know that writing an own strcpy with a simple char-by-char copy is easy, but I thought that the standard library might apply magic which makes strcpy faster than a naive char-by-char implementation.

So, what is the best method to strcpy and receive the number of copied characters without traversing the string again?

Laquitalar answered 21/12, 2015 at 19:12 Comment(6)
strcpy is not complicated you could rite your own ...Plasmolysis
Don't see how just using strcpy. If you know the length of string being copied, then use that, as strcpy will always copy all characters from source string (including null, so it really copies strlen(src)+1 chars). Since it's C++, you could use std::string.Melson
You cold use std::strings and not have to worry about this.Trichomoniasis
Why are you so worried about traversing the strings twice? Is this really causing a performance problem in your code, or are you optimizing prematurely>?Finback
@Barmar: I am using this code in the core of a main-memory database management system implementation. It is likely to be in the hot loop of a lot of queries to be executed.Laquitalar
How about approaching this from the opposite end: 1) Call strlen on the source string; 2) Call memcpy. The idea is that memcpy may be faster than strcpy because it need not check for the terminating null, and knows the number of bytes to be copied in advance.Genteel
P
10

Many systems support stpcpy which returns pointer to the end of the destination. You can subtract original destination pointer and this way you'll get the length.

Prater answered 21/12, 2015 at 19:18 Comment(4)
Here it says that the char* returned in the same as dest ...Plasmolysis
@Ben You are linking to the strcpy documentation but @Zbynek refers to stpcpy.Ferine
This would be indeed useful, but I want to be platform independent. Does such a function exists in the standard library?Laquitalar
@gexicide: Unfortunately not, basic C library without extensions is quite limited. I believe I saw something similar for windows too but forgot the name.Prater
U
4

I would use sprintf to do the job:

size_t len_strcpy(char *dest, char const *src) { 
    return sprintf("%s", dest, src);
}

It's hard to guess whether this will really be slower or faster than using strcpy followed by strlen though. With the Microsoft compiler, for one example, they recently did some work on the implementation of sprintf and such, so (on Intel) it uses vector instructions and runs really fast. With older versions of the compiler, there would be a lot better chance of the strcpy/strlen winning.

Unlatch answered 21/12, 2015 at 19:25 Comment(2)
I imagine that parsing a format string might not be the fastest possible solution.Laquitalar
@gexicide: But, as noted in the answer, it actually works out that with at least one widely-used implementation, it's actually faster to do some string operations with sprintf (and such) than with the functions that seem like they should be faster (in some cases by a fair margin). I can't find a link at the moment, but STL mentioned it in a blog entry fairly recently. In any case, it's parsing a two-character format string, so unless the parser is really slow (or the string being copied is exceptionally short) it's not hard for it to be a win.Unlatch
P
3

If you really need this it would be very easy to write your own:

unsigned int lenstrcpy(char dest[], const char source[]) {
    unsigned int i = 0;
    while ((dest[i] = source[i]) != '\0') {
       i++;
    }
    return i; 
}

Here is a live example.

Plasmolysis answered 21/12, 2015 at 19:17 Comment(8)
It is not clear if this will be faster than using strcpy() and then strlen() as that functions are optimized for target platform.Tierney
@Tierney The OP is worrying about traversing the string twice? This solves this problem?Plasmolysis
@Ben he worries about speed and that traversing twice may slow it down, not to avoid double traverse by any costTierney
Slava is right, speed is what I am aiming for. I know that writing an own strcpy is easy, but I thought that the standard library might apply magic which makes strcpy faster than a naive char-by-char implementation.Laquitalar
@Tierney Sure, but i dont see how this would be slower then strcpy then strlen, unless the implementation is paralleled or has some special aligned memory copy. I doubt strlen especially will be any different then just iterating the string until \0 is reached.Plasmolysis
@Ben it does not have to be paralleled, for example it can copy full machine words and then rest of the string or use special assembly instructions. Note gcc has intrinsic for strcpy()Tierney
@Tierney ok, looks like some magic stuff is definitally going on: ideone.com/PZTQu5Plasmolysis
@Ben added memcpy to your code, link is in my answerTierney
T
3

I would try this - use strlen() and then memcpy() but as usual when speed is your target you better test it for target platforms, as there could be many factors that is difficult to count in theory.

Added memcpy() to Ben's speed test

on gcc 5.1.0 with -O1 results are:

  • part1: 62181 - manual copy
  • part2: 195093 - strcpy/strlen
  • part3: 45568 - strlen/memcpy

with -O2 results for part1 and part3 almost did not change, but part2 changed dramattically:

  • part1: 62234
  • part2: 12129
  • part3: 45565

looks like on -O2 optimization compiler eliminated extra call to strlen() and used cached value.

Tierney answered 21/12, 2015 at 19:39 Comment(0)
A
2

Standard C library does not offer a function that does what you want, so you need to write your own. Fortunately, it's not too complicated:

size_t StrCpyLen(char *dest, const char *src) {
    const char *s = src;
    while ((*dest++ = *s++))
        ;
    return s - src - 1;
}

Demo.

The above implementation is lifted from K&R, with a small modification: rather than using src directly, it makes a copy before running the loop, so that the length could be determined by subtracting the original src once the loop completes.

Anoxemia answered 21/12, 2015 at 19:21 Comment(3)
Is such a naive char-by-char implementation as efficient as strcpy which might apply some platform-dependent magic?Laquitalar
@Laquitalar Well, the implementation should not be compared to strcpy by itself but to strcpy+strlen called back-to-back. Although it is going to be as slow or slower than strcpy, the chances that it would outperform strcpy+strlen are reasonably high, especially for long strings, when caching starts playing a major role.Anoxemia
Late to the party, but that's only because the string in that example is a compile-time constant. As soon as you change str1 to be a dynamic string, the strcpy + strlen version becomes nearly twice as slow. ideone.com/arie8eHolcman

© 2022 - 2024 — McMap. All rights reserved.