0

I need to copy some c-like string to another and move its pointer. I wrote wrapper around strcpy that moves destination pointer and I'm wondering if there is some better way to do this.

This is what I have done for now:

#include <string.h>
#include <stdio.h>

// copy t to *s and move **s pointer to the end
void write_obj(char ** s, char * t) {
     strcpy(*s, t);
     (*s) += strlen(t);
}

void main(){
    char json_str[1024];
    char* json_str_ptr;
    char** s = &json_str_ptr;

    printf("Init:\r%08x\n", *s);

    write_obj(s, "12345678");

    printf("%08x\n", *s);

    write_obj(s, "1234");

    printf("%08x\n", *s);
}

Is there better and/or more efficient way to do this?

How about just copying char by char and increment (*s) in loop until I reach \0 in source array or end of target array?

I'm testing this now on msvc compiler, but code will target STM32 microcontroller and this will be pretty hot function.

Kamil
  • 13,363
  • 24
  • 88
  • 183

2 Answers2

1
  1. Parsing jsons usually does not require micro optimizations.
  2. IMO own function will be better than the strlen + memcpy (tested on stm32F429). memcpy optimizations are usually best fitted for longer copy operations - json strings usually are quite short.
  3. It is better to avoid side effects when possible. Use function return value instead of a double pointer.
char *copyandmove(char *dest, const char *src)
{
    while((*dest++ = *src++));
    return dest - 1;
}

int main(void)
{
    char x[100];
    char *s = x;

    s = copyandmove(s, "Hello");
    s = copyandmove(s, "");
    s = copyandmove(s, " World");

    printf("Result: `%s`\n", x);

}
0___________
  • 60,014
  • 4
  • 34
  • 74
0

if there is some better way to do this.

  1. If linux-like routines available, use *s = stpcpy(*s, t)

  2. If the compiler has good optimizations, could use *s += sprintf(*s, "%s", t);. (Fails if length exceeds INT_MAX.)

  3. Various other O(n) approaches. The restrict basically means the pointer to data of s, *s, t does not overlap.

     void write_obj(char * restrict  * restrict s, 
         const char * restrict t) {
       size_t len = strlen(t);
       memcpy(*s, t, len + 1);
       *s += len;
     }
    

What ever above approach (all O(n)) used, returning the end pointer of the string avoids the Schlemiel the Painter's algorithm problem O(n*n) of repeated strcat().

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • 1. tagged `stm32` - so no linux 2. GCC (mainly used in stm32 development) is not as good. https://godbolt.org/z/dP6hzKK1E 3. strlen + memcpy on this target is less efficient than the simply copy function. None works for stm32 target – 0___________ Nov 19 '21 at 14:52
  • @0___________ 1. Even if Linux not fully ported to stm32, a stm32 `stpcpy()` may exist or easy to make a decent one. 2. Interesting sample code. `return dest - 1;` looks amiss. I'd expect `return dest;` as return from `sprintf()` does not include the `'\0'`. 3. A simple copy with `strcpy()` still obliges a `strlen()` call to form `len`. Re: efficiency, either way is same `O(n)`. 4. "None works for stm32 target" is unclear. Are you suggesting `write_obj()` would not work on stm32? – chux - Reinstate Monica Nov 19 '21 at 18:05
  • @0___________ Perhaps we should [use](https://godbolt.org/z/G9fjqro9b) `char *copyandmove(char * restrict dest, const char * restrict src) { return dest + sprintf(dest, "%s", src); }` to let the compiler take advantage of non-overlapping data. – chux - Reinstate Monica Nov 19 '21 at 18:11
  • Your example does not show anything. It simple prints one string in the main function. `restrict` does not change anything in this case (function code). `sprintf` or `strlen + memcpy` are not too efficient for this target. https://godbolt.org/z/qPjocb63b Linux was never ported to stm32 uC as they do not have enough resources to run it (STM32MP are not uCs - they are application processors with M4 uC coprocessor). Probably it possible to port Linux to stm32H7 or stm32l4s9 processors as they have 1M and 640kB od SRAM. (H7 SRAM areas are not consecutive and it will make port much more difficult) – 0___________ Nov 19 '21 at 23:27
  • They will also require additional non volatile storage as they do not have enough FLASH to accommodate the Linux kernel. – 0___________ Nov 19 '21 at 23:27