strXcpy comparison

In the beginning, there was void.

As a C programmer you probably know strcpy(), but hopefully strncpy(), too.

But do you also know strlcpy() (from BSD) and strscpy() (from the Linux kernel)?

And do you know the suitable differences?

strcpy

char *strcpy(char *dest, const char *src);

Characteristics

  • Will copy unknown number of characters from *src to *dst until the first \0 character is reached.
  • The destination *dst must be large enough to hold the sting.
  • The trailing space of the destination is not touched.
  • It returns *dest unmodified.
  • POSIX.1-2001, POSIX.1-2008, C89, C99, SVr4, 4.3BSD.

Example

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

static const char DEFAULT[] = "text";
static char dest[sizeof DEFAULT];

int main(int argc, char **argv) {
  const char *src = argc > 1 ? argv[1] : DEFAULT;

  char *res = strcpy(dest, src);

  printf("source length=%zd\n", strlen(src));
  printf("destination length=%zd\n", strlen(dest));
  printf("returned pointer=dest+%ld\n", res - dest);
  printf("last character[%zd]=0x%02x\n", sizeof dest - 1, dest[sizeof dest - 1]);

  return 0;
}

Compilation

gcc -Wall -o strncpy strncpy.c

strncpy

char *strncpy(char *dest, const char *src, size_t n);

Characteristics

  • Will copy up to n characters from *src to *dst until the first \0 character is reached.
  • If the destination *dst is not large enough, there will be no trailing \0s.
  • The trailing space will be filled with \0.
  • It returns *dest unmodified.
  • POSIX.1-2001, POSIX.1-2008, C89, C99, SVr4, 4.3BSD.

Example

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

static const char DEFAULT[] = "text";
static char dest[sizeof DEFAULT];

int main(int argc, char **argv) {
  const char *src = argc > 1 ? argv[1] : DEFAULT;

  char *res = strncpy(dest, src, sizeof dest);

  printf("source length=%zd\n", strlen(src));
  printf("destination length=%zd\n", strlen(dest));
  printf("returned pointer=dest+%ld\n", res - dest);
  printf("last character[%zd]=0x%02x\n", sizeof dest - 1, dest[sizeof dest - 1]);
  if (dest[sizeof dest - 1]) {
    printf("TRUNCATED, Manually terminating string!\n");
    dest[sizeof dest - 1] = '\0';
  }

  return 0;
}

Compilation

gcc -Wall -o strncpy strncpy.c

strlcpy

size_t strlcpy(char *dest, const char *src, size_t size);

Characteristics

  • Will copy up to n-1 characters from *src to *dst until the first \0 character is reached.
  • Will always terminate the string with one \0 character.
  • The trailing space of the destination is not touched.
  • It returns the length of *src.
  • BSD only!

Example

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

static const char DEFAULT[] = "text";
static char dest[sizeof DEFAULT];

int main(int argc, char **argv) {
  const char *src = argc > 1 ? argv[1] : DEFAULT;

  size_t len = strlcpy(dest, src, sizeof dest);

  printf("source length=%zd\n", strlen(src));
  printf("destination length=%zd\n", strlen(dest));
  printf("returned len (of source)=%zd\n", len);
  printf("last character[%zd]=0x%02x\n", sizeof dest - 1, dest[sizeof dest - 1]);
  if (len >= sizeof dest)
    printf("TRUNCATED!\n");

  return 0;
}

Compilation

You need libbsd::

apt-get install libbsd-dev
gcc -Wall -o strlcpy strlcpy.c -lbsd

strscpy

ssize_t strscpy(char *dest, const char *src, size_t count);

Characteristics

  • Will copy up to n-1 characters from *src to *dst until the first \0 character is reached.
  • Will always terminate the string with one \0 character (if count > 0).
  • The trailing space of the destination is not touched.
  • Returns the number of characters copied excluding the terminating \0 character or -E2BIG.
  • Linux kernel only!

Example

#include <stdio.h>
#include <string.h>
#include "uapi/asm-generic/errno-base.h"

static const char DEFAULT[] = "text";
static char dest[sizeof DEFAULT];

ssize_t strscpy(char *dest, const char *src, size_t count);

int main(int argc, char **argv) {
  const char *src = argc > 1 ? argv[1] : DEFAULT;

  size_t len = strscpy(dest, src, sizeof dest);

  printf("source length=%zd\n", strlen(src));
  printf("destination length=%zd\n", strlen(dest));
  printf("copied=%zd\n", len);
  printf("last character[%zd]=0x%02x\n", sizeof dest - 1, dest[sizeof dest - 1]);
  if (len == -E2BIG)
    printf("TRUNCATED!\n");

  return 0;
}

/* dummy definitions */
#define __must_check
#define __noreturn
#define __malloc
#define _ASM_EXTABLE(a, b)
#define barrier_data(a)
#define pr_emerg(a, b)
#define BUG(a)
#define BUG_ON(a)
/* from include/linux/kernel.h */
#define REPEAT_BYTE(x)	((~0ul / 0xff) * (x))
#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
/* do not load Linux kernel headers */
#define _LINUX_BITOPS_H
#define _LINUX_LOG2_H
#define _LINUX_KERNEL_H
#define _ASM_X86_BUG_H

#include "../lib/ctype.c"
#include "../lib/string.c"

Compilation

You need the Linux source code::

apt-get install linux-source
gcc -Wall \
  -I../linux/arch/x86/include \
  -I../linux/include \
  strscpy.c
Written on January 16, 2018