여러 프로그래밍 언어에서 사용되는 문자열 타입들을 정리한 개요입니다.
시작: 2026년 1월 14일
완료: 2026년 3월 10일
출시: 2026년 3월 10일
마지막 수정: 2026년 3월 13일
문자열 타입은, 없이는 살 수 없고, 같이 살아가기도 어렵습니다.
저는 다른 곳에서 포괄적인 목록을 찾을 수 없어서 이것을 썼습니다.
많은 언어에는 사용 사례에 따라 다양한 문자열 타입이 있습니다. 저는 rust 출신이라 String, &str, Vec<char>라는 3가지 주요 문자열 타입이 있습니다. 이것만 해도 어떤 사람들에게는 너무 많은 문자열 타입일 수 있습니다. 그러니 제가 찾을 수 있는 언어들의 문자열 타입을 모두 되짚어 봅시다.
Rust에는 주로 String, &str, Vec<char>가 있습니다. 그렇다면 이들은 각각 무엇을 할까요?
이 타입들 중 어느 것도 null-terminated가 아닙니다.
char는 유니코드 코드 포인트입니다(32비트 정수).
Vec<char>는 주로 어떤 이유로든 개별 char를 수정하거나 개수를 세고 싶을 때 사용됩니다. Vec<char>는 String으로 변환할 수 있고 그 반대도 가능합니다. Vec<char>에는 기본 문자열 출력이 없어서 실제 문자열 타입으로 쓰기에는 더 불편하지만, 그래도 문자열의 성질은 가지고 있습니다.
String은 본질적으로 확장 가능한 char 배열입니다. String 타입은 연관 함수가 붙은 Vec<char>와 비슷합니다. 내부적으로 String은 vec라는 하나의 필드를 가지며 타입은 Vec<u8>입니다.
str도 있는데, 이것은 unsized 타입이며 바이트 시퀀스로 표현됩니다. str은 또한 항상 UTF-8을 준수합니다. rust에서 unsized 타입이라는 것은 컴파일 시점에 타입의 크기를 알 수 없다는 뜻입니다. 컴파일 시점에 크기를 알 수 없기 때문에 str은 직접 만들 수 없습니다. 이런 unsized 특성이 &str이 해결하는 문제를 만듭니다.
그렇다면 &str은 무엇일까요? 메모리에서의 크기는 알 수 없지만 &가 그것을 참조해서 우리에게 sized가 되도록 만들어 줍니다.
&mut str도 있습니다. &mut str은 각 문자를 변경할 수 있는, 확장 불가능한 문자 배열입니다.
String과 &str은 또한 특별한 관계를 가집니다. &str은 _slice_처럼 동작할 수 있는데, rust 용어로는 String 내용의 일부분을 가리키는 참조를 의미합니다.
Rust와 운영체제의 문자열 타입 사이의 중간 매개체 역할을 하는 OsString과 OsStr도 있습니다.
OsString과 OsStr의 관계는 String과 &str의 관계와 같습니다. OsString의 표현은 플랫폼마다 다릅니다. 운영체제가 windows라면 wtf-8으로 표현되고, linux라면 일반 바이트로 표현됩니다.
CString과 CStr도 String과 &str과 같은 관계를 가집니다. 이들은 또한 0으로 끝나는 바이트 목록으로 인코딩됩니다.
char * / char []는 C에서 가장 흔한 문자열 타입이며 보통 immutable이고 확장 불가능합니다. 또한 여기에 연결된 메모리를 항상 소유하는 것도 아닙니다. 이것은 \0 바이트로 null-terminated됩니다. char는 최소 1바이트 크기이기도 합니다.
메모리를 직접 소유하면서 확장 가능하고 mutable하게 만들고 싶을 때도 있습니다. 이런 확장 가능한 문자열은 자신이 소유하고 메모리를 직접 관리해야 하는 char *를 할당해서 만들 수 있습니다.
const char *도 있는데, 이것은 char를 변경 가능하게 두지 않습니다.
배열 길이가 N인 char [N]도 있으며, 이것은 null-terminated일 필요는 없지만 그렇게 할 수는 있습니다.
wchar_t *도 있는데, 크기는 2바이트 또는 4바이트일 수 있습니다. 상황은 char *와 같고 보통 utf-16 또는 utf-32로 사용됩니다.
각각의 유니코드 코드 포인트 크기에 맞춰 사용하는 char16_t, char32_t, char8_t도 있습니다.
C++은 C의 상위 집합이므로 비슷한 기능이 많지만 더 많습니다!
C++에는 basic_string<char>인 string이 있습니다. 그렇다면 basic_string은 무엇일까요?
basic_string은 문자와 비슷한 객체들의 시퀀스입니다. basic_string은 문자 자체나 그 문자에 대한 연산에 의존하지 않기 때문에 매우 일반적입니다.
내부적으로 basic_string<T>도 확장 가능하며 각 T는 변경 가능합니다. 또한 basic_string은 내부적으로 길이도 저장합니다.
다음은 C++ 문자열과 그에 대응하는 타입의 표입니다:
| Type | Definition |
|---|---|
std::string | std::basic_string<char> |
std::wstring | std::basic_string<wchar_t> |
std::u8string | std::basic_string<char8_t> |
std::u16string | std::basic_string<char16_t> |
std::u32string | std::basic_string<char32_t> |
Go에는 string, []byte, []rune가 있습니다.
이 타입들 중 어느 것도 null-terminated가 아닙니다.
string은 메모리상에서 길이와 함께 바이트를 가리키는 포인터인 단순한 문자열 타입입니다. 이것도 immutable이며 확장 불가능한데, 그저 메모리 어딘가에 존재하기 때문입니다.
[]byte는 바이트 배열입니다. 이 바이트 배열은 원하는 크기까지 확장할 수 있고 변경 가능합니다. 하지만 이 바이트들은 유니코드 인코딩을 고려하지 않는데, 그 부분에서 rune이 등장합니다.
[]rune는 rune 배열이며 이것도 확장 가능하고 변경 가능합니다. rune은 유니코드를 인식하는 문자입니다. 본질적으로 32비트 길이의 정수입니다.
Zig에는 엄밀히 말해 이름 붙은 문자열 타입은 없지만, []const u8, []u8, [:0]const u8, [N]u8, [N:0]u8, ArrayList(u8)가 있습니다.
[]const u8는 immutable이고 null-terminated가 아니며 확장 불가능한 바이트 배열입니다. 이것은 rust의 &str이나 go의 string에 해당합니다.
[]u8는 mutable이고 확장 불가능하며 null-terminated가 아닌 바이트 배열입니다. go의 []byte에 해당합니다.
[:0]const u8는 immutable이고 확장 불가능하며 null-terminated된 바이트 배열입니다. C의 char []와 더 비슷하지만 immutable입니다.
[:0]u8는 mutable이고 null-terminated이며 확장 불가능한 바이트 배열입니다. C의 char []에 해당합니다.
[N]u8는 크기가 N인 배열로, 확장 불가능하고 mutable이며 null-terminated가 아닙니다.
[N:0]u8는 null-terminated이며, 그 외에는 [N]u8와 같습니다.
ArrayList(u8)는 확장 가능하고 null-terminated가 아니며 mutable인 바이트 배열입니다.
ArrayListSentinel(u8, 0)은 확장 가능하고 null-terminated이며 mutable인 바이트 배열입니다.
이 모든 타입은 zig에서 서로 다른 사용 사례 속에서 조합되어 문자열로 사용됩니다.
Zig 문자열은 보통 기본적으로 유니코드를 준수하지 않으며, 그것은 의도된 설계입니다. 이것은 유니코드 코드 포인트인 u21을 사용해 우회할 수 있습니다. rust의 Vec<char>와 비슷하게 유니코드 코드 포인트 목록인 ArrayList(u21)를 만들 수 있습니다.
String은 유니코드를 인식하는 immutable이고 확장 불가능한 바이트 배열입니다.
StringBuilder는 유니코드를 인식하는 mutable이고 확장 가능한 바이트 배열입니다. 보통 문자열을 만들 때 사용됩니다.
StringBuffer도 있는데, 이것은 유니코드를 인식하는 mutable이고 확장 가능한 바이트 배열이지만 스레드 안전하기도 합니다.
char도 사용할 수 있는데, 이것은 utf-16 코드 포인트입니다. 보통은 많이 쓰이지 않습니다. 하지만 배열로 사용해서 문자열 타입처럼 쓸 수는 있습니다.
C#에는 string, cstring, StringBuilder, char [], char *가 있습니다.
string은 immutable이고 확장 불가능한 바이트 목록입니다. 유니코드를 인식하지 않습니다.
cstring은 string의 null terminated 버전입니다.
char []와 char *는 mutable이고 확장 불가능한 char 목록입니다. char는 2바이트이므로 utf-16 코드 포인트입니다.
마지막으로 StringBuilder가 있는데, 이것은 java의 StringBuilder와 거의 같습니다. mutable이고 확장 가능하며 null-terminated가 아닌 바이트 배열입니다.
Python 문자열 타입은 str과 list[str] 형태로 나옵니다.
str은 immutable이고 확장 불가능한 문자 목록입니다.
직관과는 반대로 list[str]는 mutable이고 확장 가능한 문자 목록입니다. 이것은 제자리에서 수정할 수 있습니다.
Swift는 문자열에 대해 전통적이지 않은 접근을 합니다. 여기에는 String, NSString라는 문자열 타입이 있습니다.
Swift의 String은 그래프미 클러스터인 Character들로 구성됩니다. 이것은 Character의 길이가 문자에 따라 가변적이라는 뜻입니다. 하나의 문자는 사람이 인식하는 하나의 문자입니다. e는 한 문자이고, é도 한 문자입니다. 이 타입은 변경도 가능하며, 쓰기 시 복사가 일어납니다.
Character와 함께 Unicode.Scalar도 있는데, 이는 rust의 char와 비슷하게 utf-32 코드 포인트처럼 동작합니다.
유니코드 문자로 사용되는 UInt16, UInt8도 있습니다.
Swift에는 또한 utf-16 기반이며 참조 타입인 Objective-C 문자열 타입 NSString도 있습니다. 그리고 그 mutable 변형인 NSMutableString도 있습니다.
Pascal에는 String, ShortString, AnsiString, UnicodeString, UTF8String, UTF16String, WideString이 있습니다.
String은 {$H}가 무엇인지에 따라 ShortString일 수도 있고 AnsiString일 수도 있습니다. Pascal에 익숙하지 않다면 {$H}가 무엇인지 아마 모를 것입니다. {$H}는 AnsiString을 켜는 컴파일러 지시문입니다. {$H}가 켜져 있으면 String은 ShortString 대신 AnsiString입니다.
그렇다면 ShortString은 무엇일까요? ShortString은 최대 255자의 길이를 가집니다. 내부 구조는 문자 배열이지만 첫 바이트에는 문자열의 길이가 들어 있습니다. 각 문자는 1바이트입니다.
AnsiString은 길이 제한이 없고 참조 카운팅되며 항상 null-terminated됩니다. 내부적으로 참조 카운트에 8바이트, 문자열 길이에 8바이트가 할당됩니다. AnsiString은 힙에 할당되기도 합니다. 각 문자 역시 1바이트입니다.
UnicodeString은 AnsiString과 같은 구조를 가지지만, 각 문자가 1바이트인 일반 문자를 사용하는 대신 크기가 2바이트인 WideChar를 사용합니다.
오래된 pascal 버전에서는(FPC 2.7.1 이전) UTF8String이 AnsiString의 별칭이었습니다. 더 최근의 pascal 버전에서는(FPC 2.7.1 이상) 이제 UTF8String이 UTF8String = type AnsiString(CP_UTF8)로 정의됩니다. 이제 각 문자의 길이는 1바이트에서 4바이트가 될 수 있습니다.
UTF16String은 WideString의 별칭입니다. 그렇다면 WideString은 무엇일까요?
WideString은 길이를 위해 8바이트를 두고, 그 뒤에 문자 시퀀스가 오는 레이아웃을 가집니다. 이 시퀀스는 null-terminated됩니다. 각 문자는 UTF16으로 인코딩되어 2바이트 크기입니다.
제가 이것을 충분히 잘 설명할 수 있을 것 같지는 않으니, 다음 글을 읽는 것을 권합니다: https://hasufell.github.io/posts/2024-05-07-ultimate-string-guide.html
Lemon Donnelly © 2026