문자열 및 문자 리터럴(C++)

C++를 사용하면 다양한 문자열 및 문자 형식이 지원되며 이러한 각 형식의 리터럴 값을 표현할 수 있습니다. 소스 코드에서는 문자 집합을 사용하여 문자 및 문자열 리터럴의 내용을 표현합니다. 유니버설 문자 이름 및 이스케이프 문자를 사용하면 기본 소스 문자 집합만 사용하여 모든 문자열을 표현할 수 있습니다. 원시 문자열 리터럴을 사용하면 이스케이프 문자를 사용하지 않아도 되며 원시 문자열 리터럴을 사용하여 모든 유형의 문자열 리터럴을 표현할 수 있습니다. 추가 생성 또는 변환 단계를 수행할 필요 없이 std::string 리터럴을 생성할 수 있습니다.

#include <string>
using namespace std::string_literals; // enables s-suffix for std::string literals

int main()
{
    // Character literals
    auto c0 =   'A'; // char
    auto c1 = u8'A'; // char
    auto c2 =  L'A'; // wchar_t
    auto c3 =  u'A'; // char16_t
    auto c4 =  U'A'; // char32_t

    // Multicharacter literals
    auto m0 = 'abcd'; // int, value 0x61626364

    // String literals
    auto s0 =   "hello"; // const char*
    auto s1 = u8"hello"; // const char* before C++20, encoded as UTF-8,
                         // const char8_t* in C++20
    auto s2 =  L"hello"; // const wchar_t*
    auto s3 =  u"hello"; // const char16_t*, encoded as UTF-16
    auto s4 =  U"hello"; // const char32_t*, encoded as UTF-32

    // Raw string literals containing unescaped \ and "
    auto R0 =   R"("Hello \ world")"; // const char*
    auto R1 = u8R"("Hello \ world")"; // const char* before C++20, encoded as UTF-8,
                                      // const char8_t* in C++20
    auto R2 =  LR"("Hello \ world")"; // const wchar_t*
    auto R3 =  uR"("Hello \ world")"; // const char16_t*, encoded as UTF-16
    auto R4 =  UR"("Hello \ world")"; // const char32_t*, encoded as UTF-32

    // Combining string literals with standard s-suffix
    auto S0 =   "hello"s; // std::string
    auto S1 = u8"hello"s; // std::string before C++20, std::u8string in C++20
    auto S2 =  L"hello"s; // std::wstring
    auto S3 =  u"hello"s; // std::u16string
    auto S4 =  U"hello"s; // std::u32string

    // Combining raw string literals with standard s-suffix
    auto S5 =   R"("Hello \ world")"s; // std::string from a raw const char*
    auto S6 = u8R"("Hello \ world")"s; // std::string from a raw const char* before C++20, encoded as UTF-8,
                                       // std::u8string in C++20
    auto S7 =  LR"("Hello \ world")"s; // std::wstring from a raw const wchar_t*
    auto S8 =  uR"("Hello \ world")"s; // std::u16string from a raw const char16_t*, encoded as UTF-16
    auto S9 =  UR"("Hello \ world")"s; // std::u32string from a raw const char32_t*, encoded as UTF-32
}

문자열 리터럴에는 각각 좁은 문자(싱글바이트 또는 멀티바이트), UTF-8, 와이드 문자(UCS-2 또는 UTF-16), UTF-16 및 UTF-32 인코딩을 나타내는 접두사 또는 u8LuU 두사를 가질 수 없습니다. 원시 문자열 리터럴은 이러한 인코딩의 원시 버전에 해당하는 R, u8R, LR, uR, UR 접두사를 가질 수 있습니다. 임시 또는 정적 std::string 값을 만들려면 접미사와 함께 문자열 리터럴 또는 원시 문자열 리터럴을 s 사용할 수 있습니다. 기본 소스 문자 집합, 범용 문자 이름 및 소스 코드의 확장된 코드 페이지의 문자 사용에 대한 자세한 내용은 문자 집합을 참조하세요.

문자 리터럴

문자 리터럴 은 상수 문자로 구성됩니다. 작은따옴표로 둘러싸인 문자로 표시됩니다. 문자 리터럴에는 5가지 종류가 있습니다.

  • 형식 char의 일반 문자 리터럴(예: 'a'
  • 예를 들어 형식의 char UTF-8 문자 리터럴(char8_t C++20) u8'a'
  • wchar_t형식의 와이드 문자 리터럴(예: L'a')
  • 형식 char16_t의 UTF-16 문자 리터럴(예: u'a'
  • 형식 char32_t의 UTF-32 문자 리터럴(예: U'a'

문자 리터럴에 사용되는 문자는 예약된 문자 백슬래시(\), 작은따옴표(') 또는 줄 바꿈을 제외한 모든 문자일 수 있습니다. 예약된 문자는 이스케이프 시퀀스를 사용하여 지정할 수 있습니다. 문자는 형식이 문자를 저장할 수 있을 만큼 큰 경우 유니버설 문자 이름을 사용하여 지정할 수 있습니다.

인코딩

문자 리터럴은 접두사에 따라 다르게 인코딩됩니다.

  • 접두사 없는 문자 리터럴은 일반 문자 리터럴입니다. 실행 문자 집합이 나타낼 수 있는 단일 문자, 이스케이프 시퀀스 또는 범용 문자 이름을 포함하는 일반 문자 리터럴의 값은 실행 문자 집합에서 인코딩의 숫자 값과 같은 값을 줍니다. 둘 이상의 문자, 이스케이프 시퀀스 또는 범용 문자 이름을 포함하는 일반 문자 리터럴은 다중 문자 리터럴입니다. 실행 문자 집합에 문자를 나타낼 수 없는 경우 인 코딩할 수 없는 문자 리터럴입니다. 다중 문자 리터럴과 인코딩할 수 없는 문자 리터럴에는 형식 int이 있으며 해당 값은 구현 정의됩니다. MSVC의 경우 아래의 Microsoft 관련 섹션을 참조하세요. 실행 문자 집합은 컴파일 시간에 정의되며 기본적으로 호스트 머신의 코드 페이지로 설정됩니다. 스위치를 사용하여 실행 문자 집합을 /execution-charset 설정할 수 있습니다.
  • 접두사로 L 시작하는 문자 리터럴은 와이드 문자 리터럴입니다. 단일 문자, 이스케이프 시퀀스 또는 유니버설 문자 이름을 포함하는 와이드 문자 리터럴의 값은 표준에서 실행 와이드 문자 집합을 호출하는 인코딩의 숫자 값과 같으며, Windows UTF-16으로 정의됩니다. 실행 와이드 문자 집합에 문자에 표현이 없으면 오류가 발생합니다.
  • 접두사로 u8 시작하는 문자 리터럴은 UTF-8 문자 리터럴입니다. 단일 문자, 이스케이프 시퀀스 또는 범용 문자 이름을 포함하는 UTF-8 문자 리터럴 값은 단일 UTF-8 코드 단위(C0 컨트롤 및 기본 라틴어 유니코드 블록에 해당)로 나타낼 수 있는 경우 ISO 10646 코드 포인트 값과 같은 값을 가집니다. 값을 단일 UTF-8 코드 단위로 나타낼 수 없는 경우 프로그램이 잘못된 형식입니다. 둘 이상의 문자, 이스케이프 시퀀스 또는 범용 문자 이름을 포함하는 UTF-8 문자 리터럴의 형식이 잘못되었습니다.
  • 접두사로 u 시작하는 문자 리터럴은 UTF-16 문자 리터럴입니다. 단일 문자, 이스케이프 시퀀스 또는 범용 문자 이름을 포함하는 UTF-16 문자 리터럴 값은 단일 UTF-16 코드 단위(기본 다국어 평면에 해당)로 나타낼 수 있는 경우 해당 ISO 10646 코드 포인트 값과 같은 값을 가집니다. 단일 UTF-16 코드 단위로 값을 나타낼 수 없는 경우 프로그램의 형식이 잘못되었습니다. 둘 이상의 문자, 이스케이프 시퀀스 또는 범용 문자 이름을 포함하는 UTF-16 문자 리터럴의 형식이 잘못되었습니다.
  • 접두사로 U 시작하는 문자 리터럴은 UTF-32 문자 리터럴입니다. 단일 문자, 이스케이프 시퀀스 또는 범용 문자 이름을 포함하는 UTF-32 문자 리터럴의 값은 ISO 10646 코드 포인트 값과 같은 값을 가집니다. 둘 이상의 문자, 이스케이프 시퀀스 또는 범용 문자 이름을 포함하는 UTF-32 문자 리터럴의 형식이 잘못되었습니다.

이스케이프 시퀀스

이스케이프 시퀀스에는 단순, 숫자 및 범용의 세 가지 종류가 있습니다. 이스케이프 시퀀스는 다음 값 중 어느 것이든 될 수 있습니다.

이스케이프 시퀀스
줄 바꿈 \n
백슬래시 \\
가로 탭 \t
물음표 ? 또는 \?
세로 탭 \v
작은따옴표 \'
백스페이스 \b
큰따옴표 \"
캐리지 리턴 \r
폼 피드 \f
경고(벨) \a
null 문자 \0
8진수 \ooo
구분된 8진수(C++23) \o{OOO}
16진수 \xhhh
구분된 16진수(C++23) \x{hhhh}
범용 문자 \uHHHH 또는 \UHHHHHHHH
구분된 범용(C++23) \u{HHHH}
명명된 범용(C++23) \N{UNIVERSAL CHARACTER NAME}

이 샘플 코드는 일반 문자 리터럴을 사용하는 간단한 이스케이프 시퀀스의 예를 보여 줍니다. 동일한 이스케이프 시퀀스 구문은 다른 문자 리터럴 형식에 유효합니다.

#include <iostream>
using namespace std;

int main() {
    char newline = '\n';
    char tab = '\t';
    char backspace = '\b';
    char backslash = '\\';
    char nullChar = '\0';

    cout << "Newline character: " << newline << "ending" << endl;
    cout << "Tab character: " << tab << "ending" << endl;
    cout << "Backspace character: " << backspace << "ending" << endl;
    cout << "Backslash character: " << backslash << "ending" << endl;
    cout << "Null character: " << nullChar << "ending" << endl;
}
/* Output:
Newline character:
ending
Tab character:  ending
Backspace character:ending
Backslash character: \ending
Null character: ending
*/

백슬래시 문자(\)는 줄 끝에 배치되는 줄 연속 문자입니다. 백슬래시 문자가 문자 리터럴로 표시되도록 하려면 두 개의 백슬래시(\\)를 연속하여 입력해야 합니다. 줄 연속 문자에 대한 자세한 내용은 Phases of Translation를 참조하세요.

숫자 이스케이프 시퀀스에는 8진수 및 16진수 이스케이프 시퀀스가 포함됩니다. 이러한 시퀀스는 컴파일러가 이를 평가할 때 숫자 값을 생성합니다.

8진수 이스케이프 시퀀스는 백슬래시 뒤에 1~3개의 8진수 숫자로 이루어져 있습니다. 8진수 이스케이프 시퀀스는 8진수가 아닌 첫 번째 문자에서 종료됩니다(세 번째 숫자보다 빨리 발생하는 경우). 가능한 가장 높은 8진수 값은 \377. C++23에는 백슬래시 뒤에 문자, 8진수 문자 시퀀스, 일치하는 }문자o{로 구성된 구분된 8진수 시퀀스가 추가되었습니다. 구분된 8진수 시퀀스에서 가능한 가장 높은 값은 해당 값이 속한 문자 리터럴의 형식에 따라 결정됩니다.

8진수 이스케이프 시퀀스를 사용할 때 일반적인 실수는 시퀀스가 8진수 이상을 허용하거나 8진수가 아닌 숫자로 시퀀스를 일찍 종료하는 것입니다. 일반 문자 리터럴이 아닌 경우 이 실수를 하면 리터럴이 다자간 리터럴로 바뀝니다.

char c1 = '\100';   // Okay, '@'
char c2 = '\1000';  // multicharacter literal, truncates to '0'
char c3 = '\009';   // multicharacter literal, truncates to '9'

구분된 8진수 시퀀스를 사용하여 이 실수를 방지할 수 있습니다.

char c1 = '\o{100}';   // Okay, '@'
char c2 = '\o{1000}';  // error, value is out of range for char
char c3 = '\o{009}';   // error, non-octal value inside octal sequence.

16진수 이스케이프 시퀀스는 백슬래시 뒤에 문자 x와 하나 이상의 16진수 숫자가 뒤따르는 방식입니다. 앞에 오는 0은 무시됩니다. C++23에는 백슬래시로 구성된 구분된 16진수 시퀀스와 문자 x{, 16진수 문자 시퀀스, 일치하는 }문자가 추가되었습니다. 일반 또는 u8접두사 문자 리터럴에서 가장 높은 16진수 값은 0xFF. L접두사 또는 u접두사 문자 리터럴에서 가장 높은 16진수 값은 0xFFFF. U접두사 문자 리터럴에서 가장 높은 16진수 값은 0xFFFFFFFF.

유니버설 문자 이름

문자 리터럴 및 네이티브(원시가 아닌) 문자열 리터럴에서 범용 문자 이름을 사용하여 모든 문자를 나타냅니다. 유니버설 문자 이름은 접두 \U 사 뒤에 8자리 유니코드 코드 포인트 또는 접두 \u 사 뒤에 네 자리 유니코드 코드 포인트를 사용합니다. 올바른 형식의 유니버설 문자 이름을 만들려면 8~4자리 숫자를 모두 포함해야 합니다. C++23에서는 구분된 유니버설 문자와 명명된 유니버설 문자가 도입되었습니다. 구분된 범용 문자는 접두 \u{사로 구성되고 그 뒤에 일련의 16진수 문자가 뒤에 잇 }습니다. 명명된 유니버설 문자는 접두 \N{사로 구성되고 그 뒤에 유니버설 문자 이름이 뒤에 잇습니다 }. 대/소문자를 구분하는 유니버설 문자 이름은 유니코드 컨소시엄의 유니코드 문자 데이터베이스의 이름과 일치해야 합니다. 컴파일러는 시스템에 설치된 유니코드 버전을 사용하여 문자 값을 확인합니다.

char u1 = 'A';          // 'A'
char u2 = '\101';       // octal, 'A'
char u3 = '\x41';       // hexadecimal, 'A'
char u4 = '\u0041';     // UCN 'A'
char u5 = '\U00000041'; // UCN 'A'
char u6 = '\u{41}';     // UCN 'A'
char u7 = '\N{LATIN CAPITAL LETTER A}'; // UCN 'A'

다문자 및 인코딩할 수 없는 문자 리터럴

다중 문자 리터럴은 여러 문자와 접두사를 사용하지 않는 일반 문자 리터럴입니다. 'AB' 는 다중 문자 리터럴의 예입니다.

인코딩할 수 없는 문자 리터럴은 단일 char 값으로 인코딩할 수 없는 문자를 포함하는 접두사 없이 문자 리터럴입니다. 예를 들어 유니코드 문자 U+1F609 '😉'는 단일 char 8비트 값으로 인코딩할 수 없도록 UTF-8로 나타내는 데 4바이트가 걸리기 때문입니다.

컴파일러는 다문자와 인코딩할 수 없는 문자 리터럴을 유사하게 처리합니다. 해당 형식은 int 런타임 시 해당 값이 구현에 정의되어 있습니다. 자세한 내용은 아래 Microsoft 관련 섹션을 참조하세요. 와 같은 U'😉'문자 접두사를 사용하여 구현 정의 동작을 방지할 수 있습니다.

Microsoft 전용

값이 32비트 정수 값에 매핑되므로 다중 문자 리터럴의 최대 문자 시퀀스는 4입니다. 문자가 4자 미만이면 컴파일러는 상위 비트를 0으로 채운다.

int c1 = 'a';   // 0x00000061 (not a multicharacter literal)
int c2 = 'ab';  // 0x00006162
int c3 = 'abc'; // 0x00616263
int c4 = 'abcd';// 0x61626364

일반 문자를 정수로 매핑하면 결과 정수의 값이 대상 컴퓨터의 엔디언과 독립적입니다. 따라서 작은 엔디안 컴퓨터에서 메모리의 개별 문자 값 순서가 대칭 이동되고 해당하는 문자열 값과 일치하지 않습니다.

int ch = 'abcd'; // 'd' is first in memory on little endian machines
const char* str = "abcd";
// compare the first byte of str with the last byte of ch
if(str[0] == reinterpret_cast<const char*>(&ch)[3])
{
    printf("little-endian\n");
}

다중 문자 리터럴에 사용되는 정수 이스케이프 시퀀스는 8비 char 트 값에 맞아야 합니다. 일반 문자 시퀀스와 달리 다중 문자 리터럴 내의 이스케이프된 값은 대상 컴퓨터의 엔디언성에 따라 인코딩됩니다. 즉, 시퀀스의 결과 값이 little endian 머신에서 대칭 이동됩니다. 컴파일러는 상위 비트를 0으로 채운다.

int ch1 = '\x61';            // 0x00000061 (not a multicharacter literal)
int ch2 = '\x61\x62';        // 0x00006261
int ch3 = '\x61\x62\x63';    // 0x00636261
int ch4 = '\x61\x62\x63\x64';// 0x64636261

단일 다중 문자 리터럴에서 일반 및 정수 이스케이프 시퀀스를 혼합하지 마세요. 인코딩 규칙은 컴퓨터의 엔디언에 따라 다르므로 결과가 정의되지 않습니다.

인코딩할 수 없는 문자 리터럴로 한정되는 값의 범위는 현재 실행 문자 집합에 따라 달라집니다. 일본어 반자 간지 (U+FF82)는 3바이트를 나타내기 때문에 인코딩할 수 없는 문자 /execution-charset:utf-8 입니다. 동일한 문자는 단일 바이트로 표현될 수 있으므로 아래 /execution-charset:shift_jis 의 일반 문자 리터럴로 간주됩니다.

컴파일러는 먼저 문자를 멀티바이트 실행 문자 집합 표현으로 변환하여 정수 값을 계산한 다음 바이트 시퀀스를 정수에 매핑합니다. 컴파일러는 높은 순서의 바이트를 0으로 채깁니다.

일본어 전체 너비 간지 (U+30C4)를 예로 사용합니다. 는 UTF-8에서 3 바이트 시퀀스 0xe3 0x83 0x84 로, shift_jis 2 바이트 시퀀스 0x83 0x63로 표시됩니다.

int tsu = 'ツ'; // non-encodable character literal
if (tsu == 0xe38384)
{
    printf("detected /execution-charset:utf-8");
}
else if (tsu == 0x8363)
{
    printf("detected /execution-charset:shift_jis");
}

구현 정의 동작을 방지하고 실행 문자 집합의 영향을 받지 않는 문자의 유니코드 값을 얻으려면 다음과 같은 U'ツ'문자 접두사를 사용합니다.

Microsoft 관련 섹션은 여기에서 끝납니다.

문자열 리터럴

문자열 상수는 서로 결합되어 null로 끝나는 문자열을 만드는 문자 시퀀스를 나타냅니다. 문자를 큰따옴표로 묶어야 합니다. 다음과 같은 종류의 문자열 리터럴이 있습니다.

일반 문자열 리터럴

일반 문자열 리터럴은 접두사로 구분된 큰따옴표로 구분된 null로 끝나는 형식 const char[n]배열입니다. 여기서 n 은 배열의 길이(바이트)입니다. 일반 문자열 리터럴은 큰따옴표(), 백슬래시\(") 또는 줄 바꿈 문자를 제외한 모든 그래픽 문자를 포함할 수 있습니다. 일반 문자열 리터럴에는 이스케이프 시퀀스도 포함될 수 있습니다. 일반 문자열 리터럴에서 범용 문자 이름의 인코딩은 실행 문자 집합에 따라 달라집니다.

const char *ordinary = "abcd";

// represents the string: yes\no
const char *escaped = "yes\\no";

UTF-8 문자열 리터럴

UTF-8로 인코딩된 문자열은 u8-prefixed, 큰따옴표로 구분된 null로 끝나는 형식 const char[n]배열입니다. 여기서 n 은 인코딩된 배열의 길이(바이트)입니다. u8접두사 문자열 리터럴은 큰따옴표(), 백슬래시\(") 또는 줄 바꿈 문자를 제외한 모든 그래픽 문자를 포함할 수 있습니다. u8접두사 문자열 리터럴에는 이스케이프 시퀀스도 포함될 수 있습니다.

C++20에는 이식 가능한 char8_t (UTF-8로 인코딩된 8비트 유니코드) 문자 형식이 도입되었습니다. C++20에서는 u8 리터럴 접두사가 char8_t 대신 char의 문자 또는 문자열을 지정합니다.

// Before C++20
const char* str1 = u8"Hello World";
const char* str2 = u8"\U0001F607 is 😇";
// C++20 and later
const char8_t* u8str1 = u8"Hello World";
const char8_t* u8str2 = u8"\U0001F607 is 😇";

넓은 문자열 리터럴

와이드 문자열 리터럴은 null로 끝나는 상수 wchar_t 배열로, 'L'에 접두사를 지정하고 큰따옴표(), 백슬래시("\) 또는 줄 바꿈 문자를 제외한 모든 그래픽 문자를 포함합니다. 와이드 문자열 리터럴에는 이스케이프 시퀀스도 포함될 수 있습니다.

const wchar_t* wide = L"zyxw";
const wchar_t* newline = L"hello\ngoodbye";

UTF-16 문자열 리터럴

UTF-16 문자열 리터럴은 'u'의 접두사로 접두사로 지정된 null로 끝나는 상수 char16_t 배열이며 큰따옴표(), 백슬래시("\) 또는 줄 바꿈 문자를 제외한 모든 그래픽 문자를 포함합니다. UTF-16 문자열 리터럴에는 이스케이프 시퀀스도 포함될 수 있습니다.

const char16_t* utf_16 = u"hello 🌍";

UTF-32 문자열 리터럴

UTF-32 문자열 리터럴은 'U'의 접두사로 접두사로 지정된 null로 끝나는 상수 char32_t 배열이며 큰따옴표(), 백슬래시("\) 또는 줄 바꿈 문자를 제외한 모든 그래픽 문자를 포함합니다. UTF-32 문자열 리터럴에는 이스케이프 시퀀스도 포함될 수 있습니다.

const char32_t* utf_32 = U"hello 🌏";

원시 문자열 리터럴(C++11)

원시 문자열 리터럴은 큰따옴표(), 백슬래시\(") 또는 줄 바꿈 문자를 포함하여 그래픽 문자를 포함하는 모든 문자 형식의 null로 끝나는 배열입니다. 문자 클래스를 사용하는 정규식과 HTML 문자열 및 XML 문자열에 원시 문자열 리터럴을 사용합니다.

// represents the string: An unescaped \ character
const char* raw_narrow = R"(An unescaped \ character)";
const wchar_t*  raw_wide  = LR"(An unescaped \ character)";
const char*     raw_utf8a = u8R"(An unescaped \ character)"; // Before C++20
const char8_t*  raw_utf8b = u8R"(An unescaped \ character)"; // C++20
const char16_t* raw_utf16 = uR"(An unescaped \ character)";
const char32_t* raw_utf32 = UR"(An unescaped \ character)";

구분 기호는 원시 문자열 리터럴의 여는 괄호 바로 앞에 위치하고 닫는 괄호 바로 뒤에 오는 최대 16자의 사용자 정의 시퀀스입니다. 예를 들어 R"abc(Hello"\()abc" 에서 구분 기호 시퀀스는 abc 이고 문자열 콘텐츠는 Hello"\(입니다. 구분 기호를 사용하여 큰따옴표와 괄호를 모두 포함하는 원시 문자열을 구분합니다. 이 문자열 리터럴은 컴파일러 오류를 발생합니다.

// meant to represent the string: )"
const char* bad_parens = R"()")";  // error C2059

그러나 구분 기호를 사용하면 오류가 해결됩니다.

const char* good_parens = R"xyz()")xyz";

소스 코드에서 (이스케이프된 문자가 아닌) 줄 바꿈을 포함하는 원시 문자열 리터럴을 생성할 수 있습니다.

// represents the string: hello
//goodbye
const wchar_t* newline = LR"(hello
goodbye)";

std::string 리터럴(C++14)

std::string리터럴은 사용자 정의 리터럴(아래 참조)을 구현한 표준 라이브러리에 속하며, "xyz"s 접미사가 있는 형태로 s 표시됩니다. 이러한 종류의 문자열 리터럴은 지정한 접두사에 따라 형식std::string, std::u32stringstd::wstring또는 std::u16string형식의 임시 개체를 생성합니다. 앞의 예제와 같이 접두사를 사용하지 않으면 리터럴이 .를 std::string생성합니다. L"xyz"sstd::wstring를 생성합니다. u"xyz"sstd::u16string을 생성하고 U"xyz"s std::u32string을 생성합니다.

//#include <string>
//using namespace std::string_literals;
string str{ "hello"s };
string str2{ u8"Hello World" };     // Before C++20
u8string u8str2{ u8"Hello World" }; // C++20
wstring str3{ L"hello"s };
u16string str4{ u"hello"s };
u32string str5{ U"hello"s };

s 접미사는 원시 문자열 리터럴에서도 사용할 수 있습니다.

u32string str6{ UR"(She said "hello.")"s };

std::string리터럴은 헤더 파일의 네임스페이 <string> 스에 std::literals::string_literals 정의됩니다. 둘 다 인라인 네임스페이스로 선언되므로 컴파일러는 자동으로 네임스페std이스에 직접 속한 것처럼 처리합니다std::literals::string_literals.std::literals::string_literalsstd::literals

문자열 리터럴의 크기

ASCII char* 문자열 및 기타 싱글바이트 인코딩의 경우 문자열 리터럴의 크기(바이트)는 종료 null 문자에 1을 더한 문자 수입니다. 다른 모든 문자열 리터럴의 경우 크기는 문자 수와 엄격하게 관련되지 않습니다. UTF-8은 최대 4개의 char 요소를 사용하여 일부 를 인코딩하거나 char16_t UTF-16으로 인코딩하면 두 요소(총 4바이트)를 사용하여 단일 wchar_t를 인코딩할 수 있습니다. 이 예제에서는 와이드 문자열 리터럴의 크기(바이트)를 보여 줍니다.

const wchar_t* str = L"Hello!";
const size_t byteSize = (wcslen(str) + 1) * sizeof(wchar_t);

strlen()wcslen()는 문자열 유형의 요소 크기와 동일한 크기의 종결 null 문자를 포함하지 않습니다. char* 또는 char8_t* 문자열의 경우 1바이트, wchar_t* 또는 char16_t* 문자열의 경우 2바이트, char32_t* 문자열의 경우 4바이트입니다.

연결 후 문자열 리터럴의 최대 길이:

  • 2022 버전 17.0 이전의 Visual Studio: 연결 후 문자열 리터럴의 최대 길이는 65,535바이트입니다. 이는 좁은 문자열 리터럴과 와이드 문자열 리터럴 모두에 적용됩니다.
  • MSVC 14.51 이전: 연결 후 문자열 리터럴의 최대 길이는 사용 가능한 메모리에 의해서만 제한됩니다. 그러나 연결 전의 크기 제한은 여전히 16,384바이트입니다.
  • MSVC 14.51부터: 연결이 제거되기 전에 문자열 리터럴의 최대 길이 제한은 사용 가능한 메모리에 의해서만 제한됩니다.

문자열 리터럴 수정

문자열 리터럴은 std::string 리터럴을 포함하지 않는 한 상수이므로, 그것들을 str[2] = 'A'처럼 수정하려고 하면 컴파일러 오류가 발생합니다.

Microsoft 전용

Microsoft C++에서 문자열 리터럴을 사용하여 비 const char 또는 wchar_t.에 대한 포인터를 초기화할 수 있습니다. 이 비 const 초기화는 C99 코드에서 허용되지만 C++98에서는 더 이상 사용되지 않으며 C++11에서 제거됩니다. 문자열을 수정하려고 하면 다음 예제와 같이 액세스 위반이 발생합니다.

wchar_t* str = L"hello";
str[2] = L'a'; // run-time error: access violation

/Zc:strictStrings 컴파일러 옵션을 설정하면 문자열 리터럴이 const가 아닌 문자 포인터로 변환될 때 컴파일러가 오류를 발생시킬 수 있습니다. 표준 준수 이식 가능 코드에 사용하는 것이 좋습니다. 또한 올바른 (const) 타입으로 변환되므로 키워드를 사용하여 auto 문자열 리터럴로 초기화된 포인터를 선언하는 것이 좋습니다. 예를 들어, 이 코드 예제는 컴파일 시간에 문자열 리터럴에 쓰려는 시도를 포착합니다.

auto str = L"hello";
str[2] = L'a'; // C3892: you cannot assign to a variable that's const.

경우에 따라 실행 파일의 공간을 절약하기 위해 동일한 문자열 리터럴이 풀링될 수 있습니다. 문자열 리터럴 풀링에서 컴파일러는 각 참조가 문자열 리터럴의 별도 인스턴스를 가리키는 것이 아니라 특정 문자열 리터럴에 대한 모든 참조가 메모리의 같은 위치를 가리키게 합니다. 문자열 풀링을 사용하도록 설정하려면 컴파일러 옵션을 사용합니다 /GF .

Microsoft 관련 섹션은 여기에서 끝납니다.

인접 문자열 리터럴 연결

인접하는 와이드 문자열 리터럴 또는 좁은 문자열 리터럴은 연결됩니다. 다음 선언은

char str[] = "12" "34";

다음 선언과 동일합니다.

char atr[] = "1234";

이 선언과 동일합니다.

char atr[] =  "12\
34";

포함된 16진수 이스케이프 코드를 사용하여 문자열 리터럴을 지정하면 예기치 않은 결과가 발생할 수 있습니다. 다음 예제는 ASCII 5 문자와 f, i, v 및 e 문자가 포함된 문자열 리터럴을 만들려고 합니다.

"\x05five"

실제 결과는 16진수 5F(ASCII 코드의 밑줄)와 i, v 및 e 문자입니다. 올바른 결과를 얻으려면 다음 이스케이프 시퀀스 중 하나를 사용할 수 있습니다.

"\005five"     // Use octal literal.
"\x05" "five"  // Use string splicing.
"\x{05}five" // (C++23) delimited escape sequence

형식에 대해 정의된 basic_string 연산자를 사용하여 + 런타임에 리터럴(및 관련 std::u8string, std::u16stringstd::u32string)을 연결 std::string 합니다. 인접한 문자열 리터럴과 동일한 방식으로 컴파일 시간에 연결할 수도 있습니다. 두 경우 모두 문자열 인코딩과 각 리터럴의 접미사가 충돌해서는 안 됩니다.

auto x1 = "hello" " " " world"s; // OK, results in std::string "hello world"s
auto x2 = U"hello" " " L"world"; // C2308: disagree on prefix
auto x3 = u8"hello" " "s u8"world"z; // C3688, disagree on suffixes

범용 문자 이름을 가진 문자열 리터럴

네이티브(원시가 아닌) 문자열 리터럴은 범용 문자 이름을 문자열 형식에서 하나 이상의 문자로 인코딩할 수 있는 한 모든 문자를 나타내기 위해 범용 문자 이름을 사용할 수 있습니다. 예를 들어 ANSI 코드 페이지를 사용하는 경우 확장 문자를 나타내는 범용 문자 이름을 일반 문자열로 인코딩할 수 없지만 일부 멀티바이트 코드 페이지 또는 UTF-8 문자열 또는 와이드 문자열의 좁은 문자열로 인코딩할 수 있습니다. C++11에서 유니코드 지원은 char16_t*char32_t* 문자열 형식에 의해 확장되었고, C++20에서는 char8_t 형식으로 확장됩니다.

// ASCII smiling face
const char*     s1 = ":-)";

// UTF-16 (on Windows) encoded WINKING FACE (U+1F609)
const wchar_t*  s2 = L"😉 = \U0001F609";

// UTF-8  encoded SMILING FACE WITH HALO (U+1F607)
const char*     s3a = u8"😇 = \U0001F607"; // Before C++20
const char8_t*  s3b = u8"😇 = \U0001F607"; // C++20

// UTF-16 encoded SMILING FACE WITH OPEN MOUTH (U+1F603)
const char16_t* s4 = u"😃 = \U0001F603";

// UTF-32 encoded SMILING FACE WITH SUNGLASSES (U+1F60E)
const char32_t* s5 = U"😎 = \U0001F60E";

C++11 이상에서는 문자열 리터럴에서 사용할 때 유니버설 문자가 유니코드 스칼라 값 일 수 있습니다. 유니코드 스칼라 값에는 서로게이트 코드 포인트 범위(U+D800 ~ U+DFFF) 이외의 U+0000에서 U+10FFFF까지의 전체 유니코드 코드스페이스가 포함됩니다. C++11 이전에는 유니버설 문자가 유니코드 코드스페이스에서 기본 소스 문자 집합 및 제어 문자(U+0000에서 U+0001F 및 U+007F에서 0x9F 범위)를 제외한 모든 값이 될 수 있습니다. 유니버설 문자 이름에 대한 자세한 내용은 Character Sets을 참조하세요. 유니코드에 대한 자세한 내용은 유니코드(영문)를 참조하세요.

일반 문자열 리터럴 ""내에서 사용되는 경우 유니코드 코드 포인트는 실행 문자 집합의 코드 페이지에서 인코딩됩니다. 코드 페이지는 코드 포인트를 나타내는 데 사용되는 바이트 수뿐만 아니라 값을 제어합니다. 실행 문자 집합 코드 페이지에서 유니코드 코드 지점을 나타낼 수 없는 경우 경고가 내보내지고 문자가 코드 페이지의 기본 대체 문자로 바뀝니다. 기본 대체 문자는 코드 페이지에서 정의되며 일반적으로 U+FFFD() 또는 '?'와 같은 문자입니다. 실행 문자 집합은 컴파일러 스위치 /execution-charset에서 설정할 수 있습니다.

utf-8 리터럴 형식 u8""에서 사용되는 경우 유니코드 코드 포인트는 멀티바이트 utf-8 시퀀스로 인코딩됩니다.

16비트 문자열 리터럴 형식 L"" 에서 사용하거나 u""유니코드 코드 포인트는 UTF-16으로 인코딩됩니다. 16비트에서 맞지 않는 유니버설 문자는 자동으로 UTF-16 서로게이트 쌍으로 인코딩됩니다. 서로게이트 쌍에 대한 자세한 내용은 서로게이트 쌍 및 보조 문자를 참조하세요.

UTF-32 리터럴 형식 U""에서 사용되는 경우 유니코드 코드 포인트는 UTF-32로 인코딩됩니다.

참조 항목

문자 집합
숫자형, 불리언 및 포인터 리터럴
서로게이트 쌍 및 보조 문자
유니코드
사용자 정의 리터럴