Computer >> 컴퓨터 >  >> 프로그래밍 >> C 프로그래밍

C/C++에서 strncpy()가 안전하지 않은 함수로 간주되는 이유

strncpy() 함수는 원본(source) 문자열에서 지정된 개수만큼의 문자를 대상(destination) 배열로 복사하는 데 사용됩니다. 이름만 보면 strcpy()보다 더 안전해 보이지만, 실제로는 주의하지 않으면 심각한 문제를 일으킬 수 있는 함수입니다.

strncpy()의 기본 구문

char *strncpy( char *destination, char *source, size_t n);

각 매개변수의 의미는 다음과 같습니다.

  • destination: 원본 문자열이 복사되어 저장될 대상 배열을 가리키는 포인터
  • source: 복사할 원본 문자열
  • n: 원본 문자열에서 복사할 최대 문자 수

strncpy()가 위험한 이유

strncpy()가 안전하지 않다고 평가받는 가장 큰 이유는 NULL 문자('\0')에 의한 문자열 종료(null-termination)를 보장하지 않는다는 점입니다.

원본 문자열의 처음 n개 문자 안에 NULL 문자가 포함되어 있지 않으면, strncpy()는 대상 배열 끝에 NULL 문자를 붙이지 않습니다. 이렇게 되면 대상 문자열은 올바르게 종료되지 않은 상태가 되며, 이후 이 문자열을 출력하거나 다른 문자열 함수로 처리할 때 버퍼 경계를 벗어나 읽게 되어 정의되지 않은 동작(undefined behavior)이나 버퍼 오버런(buffer overrun)이 발생할 수 있습니다.

C++ 예제 코드

다음은 C++에서 strncpy()의 동작을 보여주는 프로그램입니다.

#include <iostream>
#include <cstring>
using namespace std;
int main () {
    char source[20] = "This is a string";
    char dest[20];
    strncpy(dest, source, 4);
    cout << "복사된 대상 문자열: " << dest;
    return 0;
}

실행 결과

복사된 대상 문자열: This

코드 설명

위 프로그램의 동작을 단계별로 살펴보겠습니다.

  1. 먼저 원본 문자열 source에는 "This is a string"이라는 데이터가 저장됩니다.
  2. strncpy(dest, source, 4)를 호출하면 원본 문자열의 처음 4개 문자("This")만 대상 배열로 복사됩니다.
  3. 이때 복사된 4개의 문자 중에는 NULL 문자가 없으므로, dest는 널 종료되지 않은 상태가 됩니다.
  4. 마지막으로 cout을 통해 대상 문자열의 내용을 출력합니다.
char source[20] = "This is a string";
char dest[20];
strncpy(dest, source, 4);
cout << "복사된 대상 문자열: " << dest;

이 예제에서는 우연히 정상적인 결과처럼 보일 수 있지만, 이는 메모리 상태에 운에 좌우되는 결과입니다. dest가 널 종료되지 않았기 때문에 컴파일러나 실행 환경에 따라 쓰레기 값(garbage value)이 함께 출력되거나 프로그램이 비정상 종료될 수도 있습니다.

안전하게 사용하는 방법

strncpy()를 사용할 때는 복사 후 반드시 수동으로 NULL 문자를 추가해야 합니다.

strncpy(dest, source, 4);
dest[4] = '\0';  // 명시적으로 널 종료 보장

또는 널 종료를 보장하는 snprintf(), 그리고 C11 표준의 부록 K에 정의된 strcpy_s() 같은 안전한 대체 함수를 사용하는 것이 좋습니다.