strn* strl*
strlcpy 함수는 strcpy 함수(src 문자를 대상버퍼(dst)에 복사)를 대상 버퍼를 오버플로우 할 수 없는 보안 버전으로 대체하기 위한 것이다. strcat에 대한 유사한 대안을 제공하는 strlcat도 있다.
버퍼 오버플로우를 방지하는 데 사용할 수 있는 표준 C함수 인 strncpy 및 strncat은 올바르게 사용하기 어렵고 느리게 만드는 결함을 가지고 있다. strlcpy 및 strlcat 은 올바른 사용법이 가능한 한 간단하도록 설계되었다.
strlcpy와 strlcat은 Todd C. Miller와 Theo de Raadt에 의해 개발되었으며 OpenBSD 버전 2.4에서 처음 구현되었다. 이후에 libbsd를 통해 FreeBSD (버전 3.3부터), Solaris, Mac OS X 및 GNU 기반 시스템을 포함한 여러 운영 체제에서 채택되었다. 많은 애플리케이션 패키지와 라이브러리에는 glib, rsync, Samba, KDE 및 Linux 커널 자체를 포함하여 이러한 함수의 자체 사본이 포함되어 있다.
뭐 이런저런 이야기들이 많은데, 구현을 통해 어떤 차이인지 알아보자.
strn* 함수들이 strl* 함수들보다 비효율적인 이유는 dst의 맨 마지막에 널을 하나만 넣어주느냐(strlcpy) dst의 남은 공간에 size까지 널을 넣느냐의 차이 같다.
strncpy
char *ft_strncpy(char *dst, const char *src, size_t n)
{
if ((dst == NULL && src == NULL) || !n)
return (0);
while ((n--) && *src)
*dst++ = *src++;
while (n--)
*dst++ = '\0';
return (dst);
}
strlcpy
size_t ft_strlcpy(char * dst, const char *src, size_t size)
{
size_t src_len;
size_t idx;
if (dst == NULL && src == NULL)
return (0);
src_len = ft_strlen(src);
idx = 0;
while (idx < src_len && idx + 1 < size)
{
dst[idx] = src[idx];
idx++;
}
if (size > 0)
dst[idx] = '\0';
return (src_len);
}
strncat
char *ft_strncat(char *dst, const char *src, size_t n)
{
char *ret;
ret = dst;
while (*dst)
dst++;
while (n--)
if (!(*dst++ = *src++))
return ret;
*dst = 0;
return (ret);
}
strlcat
size_t ft_strlcat(char *dst, const char *src, size_t size)
{
size_t dst_len;
size_t src_len;
size_t i;
size_t j;
j = 0;
while (j < size && dst[j])
j++;
dst_len = ft_strlen(dst);
src_len = ft_strlen(src);
i = 0;
while (i < src_len && dst_len + i + 1 < size)
{
dst[dst_len + i] = src[i];
i++;
}
dst[dst_len + i] = '\0';
return (j + src_len);
}
어찌됐든 이녀석들은 정적으로 메모리에 할당된 버퍼들에 복사할때 유용하고, 만약 정적으로 할당된 dst 크기를 넘어선다면 오류가 발생한다. 따라서 함수 사용자가 잘 생각해서 사용해야한다.