맨위로가기

널 종단 문자열

"오늘의AI위키"는 AI 기술로 일관성 있고 체계적인 최신 지식을 제공하는 혁신 플랫폼입니다.
"오늘의AI위키"의 AI를 통해 더욱 풍부하고 폭넓은 지식 경험을 누리세요.

1. 개요

널 종단 문자열은 문자열의 끝을 나타내기 위해 널 문자(NUL, ASCII 코드 0)를 사용하는 문자열 표현 방식이다. C 언어에서 기본 문자열 형식으로 채택되었으며, 1970년대 PDP-11 어셈블리 언어에서 처음 사용되었다. 메모리 사용량 절감이라는 장점이 있었지만, 버퍼 오버플로우와 같은 보안 문제와 성능 저하를 야기하기도 했다. 이러한 문제점을 해결하기 위해 C++의 `std::string`, Qt의 `QString`과 같은 객체 지향 래퍼를 사용한 개선된 문자열 처리 방식이 개발되었다.

더 읽어볼만한 페이지

  • 문자열 자료 구조 - LCP 배열
    LCP 배열은 문자열 처리 알고리즘에서 접미사 배열 내 인접한 두 접미사의 최장 공통 접두사 길이를 저장하는 자료구조로, 문자열 검색 시간 향상에 기여하며, 카사이 알고리즘 등으로 선형 시간 내 계산이 가능하고, 패턴 발생 횟수 찾기 등 다양한 문자열 문제 해결에 활용됩니다.
  • 문자열 자료 구조 - 접미사 배열
    접미사 배열은 문자열의 모든 접미사를 사전 순으로 정렬했을 때 각 접미사의 시작 위치를 담은 배열로, 문자열 처리, 생물 정보학, 데이터 압축 등 다양한 분야에서 활용되며, 비교 정렬, Manber-Myers 알고리즘, SA-IS 알고리즘 등을 통해 구축된다.
  • 자료 구조 - 라우팅 테이블
    라우팅 테이블은 네트워크에서 데이터 전송 시 최적 경로를 결정하는 핵심 데이터베이스로, 라우터가 목적지 IP 주소를 기반으로 다음 홉을 결정하며 직접 연결 및 원격 네트워크 경로 정보를 저장하고 동적 라우팅 또는 수동 설정으로 관리된다.
  • 자료 구조 - 스택
    스택은 후입선출(LIFO) 원칙에 따라 데이터를 관리하는 추상 자료형으로, push 연산으로 데이터를 쌓고 pop 연산으로 가장 최근 데이터를 제거하며, 서브루틴 호출 관리, 수식 평가, 백트래킹 등에 활용된다.
널 종단 문자열

2. 역사

널 종단 문자열은 PDP-11 어셈블리 언어의 `.ASCIZ` 지시어와 PDP-10의 MACRO-10 매크로 어셈블리 언어의 `ASCIZ` 지시어에서 유래되었다. 이는 C 프로그래밍 언어 개발보다 앞선 시점이었다.[2]

2. 1. C 언어에서의 채택

C 언어가 개발될 당시 메모리가 극도로 제한적이었기 때문에, 문자열 길이를 저장하기 위해 추가적인 바이트를 사용하지 않는 널 종단 방식이 채택되었다. 데니스 리치는 문자열의 길이를 별도로 저장하는 방식(파스칼 문자열) 대신 널 종단 방식을 선택했는데, 이는 문자열 길이 제한을 피하고, 그의 경험상 개수를 유지하는 것보다 널 종단자를 사용하는 것이 더 편리하다고 판단했기 때문이다.[2][3]

이러한 결정은 CPU 명령어 집합 설계에도 영향을 미쳤다. 1970년대와 1980년대의 자일로그 Z80, DEC VAX와 같은 일부 CPU는 길이 접두사 문자열 처리를 위한 전용 명령을 가지고 있었다. 그러나 널 종단 문자열이 널리 사용되면서, CPU 설계자들은 이를 고려하기 시작했다. 예를 들어, IBM은 1992년 ES/9000 520에 "논리 문자열 지원" 명령을 추가했고, 2015년 IBM z13에는 벡터 문자열 명령을 추가했다.[4]

FreeBSD 개발자 폴-헤닝 캄프는 ''ACM 큐''에서 널 종단 문자열이 2바이트(1바이트가 아닌) 길이에 대한 승리를 "가장 비싼 1바이트 실수"라고 언급했다.[5]

2. 2. CPU 명령어 집합에 미친 영향

CPU 명령어 집합 설계에 어느 정도 영향을 미쳤다. 1970년대와 1980년대의 Zilog Z80 및 DEC VAX와 같은 일부 CPU는 길이 접두사 문자열을 처리하기 위한 전용 명령을 가지고 있었다. 그러나 널 종단 문자열이 인기를 얻으면서, CPU 설계자들은 이를 고려하기 시작했다. 예를 들어 IBM은 1992년 ES/9000 520에 "논리 문자열 지원" 명령을 추가하고, 2015년 IBM z13에 벡터 문자열 명령을 추가하는 등 널 종단 문자열 처리를 위한 하드웨어 지원을 강화했다.[4]

FreeBSD 개발자 폴-헤닝 캄프는 ''ACM 큐''에 기고하면서 널 종단 문자열이 2바이트(1바이트가 아닌) 길이에 대한 승리를 "가장 비싼 1바이트 실수"라고 언급했다.[5]

3. 구현

C 프로그래밍 언어는 널 종단 문자열을 기본 문자열 형식으로 지원한다.[24][15] C 표준 라이브러리는 널 종단 문자열 처리를 위한 다양한 함수들을 제공한다. 이러한 함수들은 다음과 같은 기능을 포함한다:


  • 문자열 길이 결정
  • 한 문자열을 다른 문자열로 복사
  • 한 문자열을 다른 문자열 뒤에 추가
  • 문자열 내 특정 문자의 처음 또는 마지막 발생 부분 찾기
  • 주어진 집합에 포함되거나 포함되지 않는 문자의 첫 발생 부분을 문자열 내에서 찾기
  • 문자열 내의 서브스트링의 첫 발생 부분을 찾기
  • 두 문자열을 사전적으로 비교하기
  • 문자열을 여러 서브스트링으로 나누기
  • 숫자값 또는 문자값을 인쇄 가능한 출력 문자열로 서식 지정
  • 인쇄 가능한 문자열을 숫자값으로 구문 분석
  • 싱글 바이트와 확장 문자 문자열 인코딩 간 상호 변환
  • 싱글 바이트나 확장 문자 문자열을 멀티 바이트 문자의 문자열과 상호 변환 (C95 이후)

4. 제한

널 종단 문자열은 구현은 간단하지만, 오류 발생 가능성과 성능 문제 등 몇 가지 제한점이 있다.


  • 보안 문제: 널 종단 방식은 보안 문제를 일으킬 수 있다.[25] 문자열 중간에 삽입된 널 바이트(null byte)는 문자열을 의도치 않게 잘라버릴 수 있으며, 널 문자를 위한 공간을 할당하지 않아 인접 메모리를 덮어쓰는 버그도 발생할 수 있다.
  • 성능 문제: 문자열 길이를 구하는 연산은 O(n)의 시간을 소요하며, 0을 저장할 수 없다는 특성 때문에 텍스트 데이터와 이진 데이터를 구분하여 처리해야 하므로 코드 중복과 오류 발생 가능성이 높아진다.


이러한 문제점들로 인해 널 종단 문자열을 사용할 때는 주의가 필요하며, 더 안전하고 효율적인 대안을 고려하는 것이 좋다. `strlcpy`와 같은 함수를 사용하여 일부 문제를 완화할 수 있지만, 완벽한 해결책은 아니다.

4. 1. 보안 문제

널 종단은 역사적으로 보안 문제를 일으켜왔다.[25] 문자열 중간에 삽입된 널 바이트는 예측하지 못하도록 문자열을 잘라버린다. 일반적인 버그는 널 문자를 위한 추가적인 공간을 할당하지 못하는 것으로, 이로 인해 인접한 메모리를 초과하여 기록되는 것이다. 또 다른 버그는 널 문자를 아예 기록하지 않는 것인데, 테스트 중에는 발견하지 못할 때가 있다. 이는 널 문자가 우연히 과거의 동일한 메모리 블록을 사용하고 있기 때문이다.[6][7]

문자열 길이를 찾는 데 시간이 많이 소요되기 때문에, 많은 프로그램은 고정 크기 버퍼에 문자열을 복사하기 전에 문자열 길이를 확인하지 않았다. 따라서 문자열이 너무 길 경우 버퍼 오버플로우를 일으켰다.[16]

0을 저장할 수 없다는 점 때문에 텍스트 데이터와 바이너리 데이터를 구분하여 별도의 함수로 처리해야 한다 (후자의 경우 데이터의 길이도 함께 제공해야 한다). 이는 코드 중복을 유발하고, 잘못된 함수가 사용될 경우 오류가 발생할 수 있다.

4. 2. 성능 문제

문자열 길이를 구하는 작업은 O(''n'')의 시간 복잡도를 가지므로, 빈번하게 호출될 경우 성능 저하를 유발할 수 있다.[7] 0을 저장할 수 없어 텍스트 데이터와 바이너리 데이터를 구분하여 별도의 함수로 처리해야 하며(후자의 경우 데이터의 길이도 함께 제공해야 한다), 이는 코드 중복 및 오류 발생 가능성을 높인다.[16]

길이를 찾는 속도 문제는 `strlcpy`와 같이 O(''n'')의 다른 연산과 결합하여 완화할 수 있지만, 항상 직관적인 API를 제공하는 것은 아니다.

5. 문자 인코딩

널 종단 문자열은 문자 배열 내에서 값이 0인 요소를 감시병으로 사용하기 때문에, 값이 0이 되는 문자를 포함하지 않는 인코딩 방식이 필요하다. 1바이트 단위로 인코딩하는 경우, 값이 0이 되는 바이트를 포함해서는 안 된다.

ASCII에서는 0x00을, 유니코드에서는 U+0000을 널 문자(NUL)로 정의하고 있기 때문에[17], 널 종단 문자열에 널 문자를 그대로 포함할 수 없다[18][19][20]。 따라서 널 문자를 포함하지 않거나, 널 문자를 다른 문자나 문자열로 대체한 ASCII나 유니코드의 하위 집합을 사용한다.

자바 문자열 클래스는 널 종단이 아니며 길이 정보를 별도로 보관하므로, 내부 문자열에 널 문자를 직접 포함할 수 있다. 그러나 인코딩을 지정하여 바이트 배열에서 자바 문자열을 생성하거나[21], 자바 네이티브 인터페이스에서 자바 문자열을 C 언어의 `char`형 널 종단 문자열로 변환할 때[22]는 수정 UTF-8이 인코딩으로 사용된다.

5. 1. UTF-8 과의 관계

널 종단 문자열은 인코딩에서 0 바이트(0x00)를 사용하지 않아야 하므로, 모든 ASCII 또는 UTF-8 문자열을 저장할 수는 없다.[8][9][10] 그러나 널 종단 문자열에 NUL을 제외한 문자, 즉 ASCII 또는 UTF-8의 하위 집합을 저장하는 것이 일반적이다.

일부 시스템에서는 널 문자(NUL)를 두 개의 0이 아닌 바이트(0xC0, 0x80)로 인코딩하는 "수정된 UTF-8"을 사용하기도 한다. 이를 통해 모든 문자열을 저장할 수 있지만, 이는 과잉 인코딩으로 간주되어 UTF-8 표준에서는 허용되지 않으며 보안 위험으로 간주된다.[17][18][19][20] 예를 들어 C0 80 NUL은 보안 확인에서는 문자열 종단으로, 실제 사용 시에는 문자로 간주될 수 있다.

UTF-16은 2바이트 정수를 사용하고, 바이트 중 하나가 0일 수 있으므로 널 종단 바이트 문자열에 저장할 수 없다. 그러나 일부 언어에서는 16비트 NUL(0x0000)로 종료되는 16비트 UTF-16 문자열을 구현하기도 한다.

5. 2. UTF-16 과의 관계

UTF-16은 2바이트 정수를 사용하며, 바이트 중 하나가 0일 수 있으므로 (ASCII 텍스트를 나타낼 때는 ''다른 모든'' 바이트가 0이다) 널 종단 바이트 문자열에 저장할 수 없다.[8] 그러나 일부 언어는 16비트 널(0x0000)로 종료되는 16비트 UTF-16 문자로 구성된 문자열을 구현한다. 이 경우, 싱글 바이트(8비트)의 널 문자를 상정하고 있는 기존의 문자열 조작 함수는 사용할 수 없으며, 16비트의 널 종단 문자열 전용의 함수가 필요하게 된다. 마이크로소프트 윈도우에서는 와이드 문자가 2바이트 문자형으로 정의되어, 와이드 문자의 배열을 UTF-16의 널 종단 문자열로 취급한다.[9][10]

6. 개선

C 문자열 처리의 오류를 줄이기 위해 다양한 시도가 이루어졌다. 주요 개선 방법은 다음과 같다.


  • 안전한 함수 추가: strdupstrlcpy와 같이 더 안전한 함수를 추가하고, gets와 같이 안전하지 않은 함수의 사용을 폐지하는 방법이 있다.
  • 객체 지향 래퍼: C 문자열을 둘러싼 객체 지향 래퍼를 추가하여 안전한 호출만 수행하도록 하는 방법이 있다. 그러나 이 방법으로도 안전하지 않은 함수를 호출하는 것이 가능하다.
  • 현대적인 라이브러리: 대부분의 최신 라이브러리는 C 문자열을 32비트 이상의 길이 값을 포함하는 구조로 대체하고, 포인터, 참조 횟수, 널 문자(NUL) 등을 추가하여 C 문자열로의 변환 속도를 높인다. 현대의 메모리 환경에서는 각 문자열에 몇 바이트를 추가하는 것이 큰 문제가 되지 않으며, 작은 문자열이 많은 경우에는 해시 테이블 등의 다른 저장 방법이 메모리를 더 절약할 수 있다. 이러한 라이브러리의 예시로는 C++ 표준 템플릿 라이브러리의 `std::string`, Qt의 `QString`, MFC의 `CString`, Core Foundation의 `CFString`, Foundation의 `NSString` 등이 있다. rope와 같은 더 복잡한 자료 구조를 사용하여 문자열을 저장하기도 한다.[23]

6. 1. 안전한 함수 추가

C 문자열 처리는 오류 발생 가능성을 줄이기 위해 많은 시도가 이루어졌다. 한 가지 방법은 `strdup`이나 `strlcpy`처럼 더 안전한 함수를 추가하고, `gets` 같이 안전하지 않은 함수의 사용을 중단하는 것이다. 다른 방법으로는 C 문자열을 객체 지향 래퍼로 감싸서 안전한 호출만 가능하게 하는 것이 있다. 하지만 안전하지 않은 함수를 호출하는 것이 아예 불가능한 것은 아니다.

6. 2. 객체 지향 래퍼

C 문자열을 둘러싼 객체 지향 래퍼를 추가하여 안전한 호출만 수행하도록 할 수 있다. 그러나 안전하지 않은 함수를 호출하는 것도 가능하다.[23]

6. 3. 현대적인 라이브러리

대부분의 최신 라이브러리는 C 문자열을 32비트 이상 길이 값을 포함하는 구조로 대체하고, 포인터, 참조 횟수, 널 문자(NUL) 등을 추가하여 C 문자열로의 변환 속도를 높인다. 현대의 메모리 환경에서는 각 문자열에 몇 바이트를 추가하는 것이 큰 문제가 되지 않으며, 작은 문자열이 많은 경우에는 해시 테이블 등의 다른 저장 방법이 메모리를 더 절약할 수 있다. 이러한 라이브러리의 예시로는 C++ 표준 템플릿 라이브러리의 `std::string`, Qt의 `QString`, MFC의 `CString`, Core Foundation의 `CFString`, Foundation의 `NSString` 등이 있다. rope와 같은 더 복잡한 자료 구조를 사용하여 문자열을 저장하기도 한다.[23]

참조

[1] 웹사이트 Chapter 15 - MIPS Assembly Language https://people.scs.c[...] 2023-10-09
[2] 학회자료 The development of the C language https://www.bell-lab[...] 1993-04
[3] 서적 History of Programming Languages ACM Press
[4] 문서 IBM z/Architecture Principles of Operation http://publibfp.dhe.[...]
[5] 간행물 The Most Expensive One-byte Mistake http://queue.acm.org[...] 2011-07-25
[6] 학술지 Perl CGI problems http://insecure.org/[...] artofhacking.com 2016-01-03
[7] 웹사이트 Null byte injection on PHP? https://security.sta[...]
[8] 웹사이트 UTF-8, a transformation format of ISO 10646 http://tools.ietf.or[...] 2013-09-19
[9] 웹사이트 Unicode/UTF-8-character table http://www.utf8-char[...] 2013-09-13
[10] 웹사이트 UTF-8 and Unicode FAQ http://www.cl.cam.ac[...] 2013-09-13
[11] 문서 文字はASCIIだけに限らないことに注意。
[12] 웹사이트 Warning C6053 | Microsoft Learn https://learn.micros[...]
[13] 학회자료 The development of the C language 1993
[14] 간행물 The Most Expensive One-byte Mistake http://queue.acm.org[...] 2011-08-02
[15] 웹사이트 The Development of the C Language http://cm.bell-labs.[...] 2011-11-09
[16] 학술지 Perl CGI problems http://artofhacking.[...] artofhacking.com 2012-01-06
[17] 웹사이트 U+0000 (NUL) Unicode Character https://www.compart.[...]
[18] 웹사이트 UTF-8, a transformation format of ISO 10646 https://datatracker.[...] 2013-09-19
[19] 웹사이트 Unicode/UTF-8-character table http://www.utf8-char[...] 2013-09-13
[20] 웹사이트 UTF-8 and Unicode FAQ http://www.cl.cam.ac[...] 2013-09-13
[21] 문서
[22] 웹사이트 Java Native Interface Specification: 4 - JNI Functions https://docs.oracle.[...]
[23] 웹사이트 std::basic_string::size, std::basic_string::length - cppreference.com https://en.cpprefere[...]
[24] 웹인용 The Development of the C Language http://cm.bell-labs.[...] 2011-11-09
[25] 저널 인용 Perl CGI problems http://insecure.org/[...] artofhacking.com 2016-01-03



본 사이트는 AI가 위키백과와 뉴스 기사,정부 간행물,학술 논문등을 바탕으로 정보를 가공하여 제공하는 백과사전형 서비스입니다.
모든 문서는 AI에 의해 자동 생성되며, CC BY-SA 4.0 라이선스에 따라 이용할 수 있습니다.
하지만, 위키백과나 뉴스 기사 자체에 오류, 부정확한 정보, 또는 가짜 뉴스가 포함될 수 있으며, AI는 이러한 내용을 완벽하게 걸러내지 못할 수 있습니다.
따라서 제공되는 정보에 일부 오류나 편향이 있을 수 있으므로, 중요한 정보는 반드시 다른 출처를 통해 교차 검증하시기 바랍니다.

문의하기 : help@durumis.com