Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Język C++ obsługuje różne typy ciągów i znaków oraz udostępnia sposoby wyrażania wartości literałów każdego z tych typów. W kodzie źródłowym wyrażasz zawartość literałów znaków i ciągów przy użyciu zestawu znaków. Uniwersalne nazwy znaków i znaki ucieczki umożliwiają wyrażenie dowolnego ciągu przy użyciu tylko podstawowego zestawu znaków źródłowych. Literał surowego tekstu pozwala uniknąć używania znaków ucieczki i może służyć do wyrażania wszystkich typów literałów tekstowych. Można również tworzyć std::string
literały bez konieczności wykonywania dodatkowej konstrukcji ani konwersji.
#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
}
Literały ciągu mogą nie mieć prefiksu lub mieć prefiksy u8
, L
, u
i U
, aby oznaczać odpowiednio kodowanie znaków wąskich (jednobajtowe lub wielobajtowe), UTF-8, znaków szerokich (UCS-2 lub UTF-16), UTF-16 i UTF-32. Literał nieprzetworzonego ciągu może mieć prefiksy R
, u8R
, LR
, uR
i UR
dla surowych odpowiedników tych kodowań. Aby utworzyć wartości tymczasowe lub statyczne std::string
, można użyć literałów ciągu lub nieprzetworzonych literałów ciągu z sufiksem s
. Aby uzyskać więcej informacji, zobacz sekcję Literały ciągów znaków poniżej. Aby uzyskać więcej informacji na temat podstawowego zestawu znaków źródłowych, uniwersalnych nazw znaków i używania znaków z rozszerzonych stron kodowych w kodzie źródłowym, zobacz Zestawy znaków.
Literały znaków
Literał znaku składa się z znaku stałego. Jest reprezentowany przez znak otoczony pojedynczymi cudzysłowami. Istnieje pięć rodzajów literałów znaków:
Zwykłe literały znaków typu
char
, na przykład'a'
Literały typu
char
UTF-8 (char8_t
na przykład w języku C++20)u8'a'
Literały o szerokim znaku typu
wchar_t
, na przykładL'a'
Literały znaków UTF-16 typu
char16_t
, na przykładu'a'
Literały znaków UTF-32 typu
char32_t
, na przykładU'a'
Znak używany do literału znaku może być dowolnym znakiem, z wyjątkiem zastrzeżonego znaku ukośnika wstecznego (\
), pojedynczego znaku cudzysłowu ('
) lub znaku nowej linii. Zastrzeżone znaki można określić przy użyciu sekwencji ucieczki. Znaki mogą być określane przy użyciu uniwersalnych nazw znaków, o ile typ jest wystarczająco duży, aby pomieścić znak.
Kodowanie
Literały znaków są kodowane inaczej na podstawie ich prefiksu.
Literał znakowy bez prefiksu jest zwykłym literałem znakowym. Wartość zwykłego literału znaku zawierającego pojedynczy znak, sekwencję ucieczki lub uniwersalną nazwę znaku, którą można przedstawić w zestawie znaków wykonywania, ma wartość równą wartości liczbowej kodowania w zestawie znaków wykonywania. Zwykły literał znaku, który zawiera więcej niż jeden znak, sekwencję ucieczki lub uniwersalny kod znakowy, jest literałem wieloznakowym. Literał wielorakowy lub zwykły literał znaku, którego nie można przedstawić w zestawie znaków wykonywania, ma typ
int
, a jego wartość jest zdefiniowana przez implementację. W przypadku programu MSVC zobacz sekcję specyficzną dla firmy Microsoft poniżej.Literał znaku rozpoczynający się od prefiksu
L
jest literałem o szerokim znaku. Wartość literału szerokoznakowego zawierającego pojedynczy znak, sekwencję ucieczki lub uniwersalną nazwę znaku ma wartość równą wartości liczbowej kodowania w zestawie znaków wykonywania, chyba że literał znaku nie ma reprezentacji w zestawie znaków wykonywania szerokoznakowych, w tym przypadku wartość jest zdefiniowana przez implementację. Wartość szerokoznakowego literału zawierającego wiele znaków, sekwencje ucieczki lub uniwersalne nazwy znaków jest określana przez implementację. W przypadku programu MSVC zobacz sekcję specyficzną dla firmy Microsoft poniżej.Literał znaku rozpoczynający się od prefiksu
u8
jest literałem UTF-8 znaków. Wartość literału UTF-8 znaków zawierającego pojedynczy znak, sekwencję ucieczki lub uniwersalną nazwę znaku ma wartość równą wartości punktu kodu ISO 10646, jeśli może być reprezentowana przez pojedynczą jednostkę kodu UTF-8 (odpowiadającą kontrolkom C0 i podstawowemu blokowi Unicode łacińskiego). Jeśli wartość nie może być reprezentowana przez pojedynczą jednostkę kodu UTF-8, program jest źle sformułowany. Literał znaków UTF-8 zawierający więcej niż jeden znak, sekwencję znaków specjalnych lub uniwersalną nazwę znaku jest niepoprawny.Literał znaku, który zaczyna się od prefiksu
u
, jest literałem znaku UTF-16. Wartość literału UTF-16 znaków zawierającego pojedynczy znak, sekwencję ucieczki lub uniwersalną nazwę znaku ma wartość równą wartości punktu kodu ISO 10646, jeśli może być reprezentowana przez pojedynczą jednostkę kodu UTF-16 (odpowiadającą podstawowej płaszczyźnie wielojęzycznej). Jeśli wartość nie może być reprezentowana przez pojedynczą jednostkę kodu UTF-16, program jest źle sformułowany. Literał znaku UTF-16 zawierający więcej niż jeden znak, sekwencję ucieczki lub uniwersalną nazwę znaku jest źle sformułowany.Literał znakowy zaczynający się od przedrostka
U
jest literałem znakowym UTF-32. Wartość literału znaków UTF-32 zawierającego pojedynczy znak, sekwencję ucieczki lub uniwersalną nazwę znaku ma wartość równą wartości punktu kodu ISO 10646. Literał znaku UTF-32 zawierający więcej niż jeden znak, sekwencję znaków sterujących lub uniwersalną nazwę znaków Unicode jest źle sformułowany.
Sekwencje ucieczki
Istnieją trzy rodzaje sekwencji ucieczki: proste, ósemkowe i szesnastkowe. Sekwencje ucieczki mogą być dowolną z następujących wartości:
Wartość | Sekwencja ucieczki |
---|---|
nowy wiersz | \n |
ukośnik odwrotny | \\ |
karta pozioma | \t |
znak zapytania | ? lub ? |
tabulator pionowy | \v |
pojedynczy cudzysłów | \' |
klawisz Backspace | \b |
podwójny cudzysłów | \" |
powrót karetki | \r |
znak null | \0 |
źródło danych formularzy | \f |
ósemkowy system liczbowy | \ooo |
alert (dzwonek) | \a |
szesnastkowo | \xhhh |
Sekwencja ucieczki ósemkowej to ukośnik odwrotny, po którym następuje sekwencja składająca się z jednej do trzech cyfr ósemkowych. Sekwencja ucieczki ósemkowej kończy się na pierwszym znaku, który nie jest cyfrą ósemkową, jeśli nastąpi to wcześniej niż po wprowadzeniu trzeciej cyfry. Najwyższa możliwa wartość ósemkowa to \377
.
Sekwencja ucieczki szesnastkowej jest ukośnikiem odwrotnym, po którym następuje znak x
, a następnie sekwencja co najmniej jednej cyfry szesnastkowej. Zera wiodące są ignorowane. W zwykłym lub z prefiksem u8 literał znakowy ma najwyższą wartość szesnastkową 0xFF. W literałie wieloznakowego z prefiksem L lub u jest to najwyższa wartość szesnastkowa 0xFFFF. W dosłownej wartości z prefiksem U najwyższa wartość szesnastkowa to 0xFFFFFFFF.
Ten przykładowy kod pokazuje kilka przykładów znaków specjalnych, wykorzystując zwykłe literały znaków. Ta sama składnia sekwencji ucieczki jest prawidłowa dla innych typów literałów znaków.
#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
*/
Znak ukośnika odwrotnego (\
) jest znakiem kontynuacji wiersza, gdy znajduje się na końcu wiersza. Jeśli chcesz, aby znak ukośnika odwrotnego był wyświetlany jako literał znakowy, musisz wpisać dwa ukośniki odwrotne pod rząd (\\
). Aby uzyskać więcej informacji na temat znaku kontynuacji wiersza, zobacz Fazy tłumaczenia.
specyficzne dla firmy Microsoft
Aby utworzyć wartość na podstawie wąskiego literału wieloznakowego, kompilator konwertuje znak lub sekwencję znaków między pojedynczymi apostrofami na wartości 8-bitowe w 32-bitowej liczbę całkowitą. Wiele znaków w literałach wypełnia odpowiednie bajty zgodnie z potrzebami z wysokiej kolejności do niskiej kolejności. Kompilator konwertuje liczbę całkowitą na typ docelowy zgodnie ze zwykłymi regułami. Na przykład, aby utworzyć wartość char
, kompilator przyjmuje bajt najmniej znaczący. Aby utworzyć wartość wchar_t
lub char16_t
, kompilator przyjmuje młodsze słowo. Kompilator ostrzega, że wynik jest obcięty, jeśli jakiekolwiek bity są ustawione powyżej przypisanego bajtu lub słowa.
char c0 = 'abcd'; // C4305, C4309, truncates to 'd'
wchar_t w0 = 'abcd'; // C4305, C4309, truncates to '\x6364'
int i0 = 'abcd'; // 0x61626364
Sekwencja ucieczki ósemkowej, która wydaje się zawierać więcej niż trzy cyfry, jest traktowana jako 3-cyfrowa sekwencja ósemkowa, a następnie kolejne cyfry jako znaki w literale wielorakterowym, co może dać zaskakujące wyniki. Na przykład:
char c1 = '\100'; // '@'
char c2 = '\1000'; // C4305, C4309, truncates to '0'
Sekwencje ucieczki, które wydają się zawierać znaki inne niż ósemkowe, są oceniane jako sekwencja ósemkowa do ostatniego znaku ósemkowego, a następnie pozostałe znaki jako kolejne znaki literału wielostopniowego. Ostrzeżenie C4125 jest generowane, jeśli pierwszy znak inny niż ósemkowy jest cyfrą dziesiętną. Na przykład:
char c3 = '\009'; // '9'
char c4 = '\089'; // C4305, C4309, truncates to '9'
char c5 = '\qrs'; // C4129, C4305, C4309, truncates to 's'
Sekwencja ucieczki ósemkowej, która ma wyższą wartość niż \377
powoduje błąd C2022: "value-in-decimal": zbyt duży dla znaku.
Sekwencja ucieczki, która wydaje się mieć znaki szesnastkowe i nieszesnastkowe, jest obliczana jako literał wielorakowy, który zawiera sekwencję ucieczki szesnastkowej do ostatniego znaku szesnastkowego, a następnie znaki nieszesnastkowe. Sekwencja ucieczki szesnastkowej, która nie zawiera cyfr szesnastkowe, powoduje błąd kompilatora C2153: "literały szesnastkowe muszą mieć co najmniej jedną cyfrę szesnastkową".
char c6 = '\x0050'; // 'P'
char c7 = '\x0pqr'; // C4305, C4309, truncates to 'r'
Jeśli literał znaku szerokiego prefiksowany L
zawiera sekwencję wieloznakową, wartość jest pobierana z pierwszego znaku, a kompilator zgłasza ostrzeżenie C4066. Kolejne znaki są ignorowane, w przeciwieństwie do zachowania równoważnego zwykłego literału wieloznakowego.
wchar_t w1 = L'\100'; // L'@'
wchar_t w2 = L'\1000'; // C4066 L'@', 0 ignored
wchar_t w3 = L'\009'; // C4066 L'\0', 9 ignored
wchar_t w4 = L'\089'; // C4066 L'\0', 89 ignored
wchar_t w5 = L'\qrs'; // C4129, C4066 L'q' escape, rs ignored
wchar_t w6 = L'\x0050'; // L'P'
wchar_t w7 = L'\x0pqr'; // C4066 L'\0', pqr ignored
Sekcja specyficzna dla firmy Microsoft kończy się tutaj.
Nazwy znaków uniwersalnych
W literałach znaków i natywnych literałach ciągu (nieprzetworzonych) każdy znak może być reprezentowany przez uniwersalną nazwę znaku. Nazwy znaków uniwersalnych są tworzone przez prefiks \U
, po którym następuje ośmiocyfrowy punkt kodu Unicode lub prefiks \u
, po którym następuje czterocyfrowy punkt kodu Unicode. Wszystkie osiem lub cztery cyfry muszą być obecne, aby utworzyć dobrze sformułowaną uniwersalną nazwę znaku.
char u1 = 'A'; // 'A'
char u2 = '\101'; // octal, 'A'
char u3 = '\x41'; // hexadecimal, 'A'
char u4 = '\u0041'; // \u UCN 'A'
char u5 = '\U00000041'; // \U UCN 'A'
Pary zastępcze
Nazwy znaków uniwersalnych nie mogą kodować wartości w zakresie punktów kodu zastępczego D800-DFFF. W przypadku par zastępczych Unicode określ uniwersalną nazwę znaku, używając \UNNNNNNNN
, gdzie NNNNNNNN jest ośmiocyfrowym punktem kodu dla znaku. Kompilator w razie potrzeby generuje parę zastępczą.
W języku C++03 język zezwalał na reprezentację podzbioru znaków tylko przez ich uniwersalne nazwy znaków i zezwalał na niektóre uniwersalne nazwy znaków, które w rzeczywistości nie reprezentują żadnych prawidłowych znaków Unicode. Ten błąd został naprawiony w standardzie C++11. W języku C++11 zarówno literały znaków, jak i ciągów oraz identyfikatory mogą używać uniwersalnych nazw znaków. Aby uzyskać więcej informacji na temat uniwersalnych nazw znaków, zobacz Zestawy znaków. Aby uzyskać więcej informacji na temat unicode, zobacz Unicode. Aby uzyskać więcej informacji na temat par zastępczych, zobacz Pary zastępcze i znaki uzupełniające.
Literały ciągu
Literał ciągu reprezentuje sekwencję znaków, które razem tworzą ciąg zakończony wartością null. Znaki muszą być ujęte między dwoma cudzysłowami. Istnieją następujące rodzaje literałów ciągów:
Wąskie literały ciągu
Literał wąskiego łańcucha znaków jest bez prefiksu, ograniczony podwójnym cudzysłowem, zakończoną nullem tablicą typu const char[n]
, gdzie n oznacza długość tablicy w bajtach. Wąski literał ciągu może zawierać dowolny znak graficzny, z wyjątkiem podwójnego cudzysłowu ("
), ukośnika odwrotnego (\
) lub znaku nowego wiersza. Wąski literał ciągu może również zawierać sekwencje ucieczki wymienione powyżej oraz uniwersalne nazwy znaków, które mieszczą się w bajtach.
const char *narrow = "abcd";
// represents the string: yes\no
const char *escaped = "yes\\no";
Ciągi zakodowane w formacie UTF-8
Ciąg zakodowany w formacie UTF-8 jest tablicą, która posiada prefiks u8, jest ograniczona podwójnymi cudzysłowami i zakończona wartością null, typu const char[n]
, gdzie n to długość tej zakodowanej tablicy w bajtach. Literał ciągu z prefiksem u8 może zawierać dowolny znak graficzny, z wyjątkiem podwójnego cudzysłowu ("
), ukośnika odwrotnego (\
) lub znaku nowego wiersza. Literał ciągu z prefiksem u8 może również zawierać sekwencje ucieczki wymienione powyżej oraz dowolną uniwersalną nazwę znaku Unicode.
Język C++20 wprowadza przenośny char8_t
typ znaku Unicode zakodowany w formacie UTF-8(UTF-8). W języku C++20 przedrostki literałów określają znaki lub ciągi jako char8_t
zamiast char
.
// Before C++20
const char* str1 = u8"Hello World";
const char* str2 = u8"\U0001F607 is O:-)";
// C++20 and later
const char8_t* u8str1 = u8"Hello World";
const char8_t* u8str2 = u8"\U0001F607 is O:-)";
Literały szerokiego ciągu
Literał szerokiego ciągu to tablica o wartości null typu stała poprzedzona znakiem wchar_t
"L
" i zawiera dowolny znak graficzny, z wyjątkiem podwójnego cudzysłowu (), ukośnika odwrotnego ("
\
) lub znaku nowego wiersza. Szeroki literał ciągu może zawierać sekwencje ucieczki wymienione powyżej i dowolną uniwersalną nazwę znaku.
const wchar_t* wide = L"zyxw";
const wchar_t* newline = L"hello\ngoodbye";
char16_t i char32_t (C++11)
Język C++11 wprowadza przenośne char16_t
typy znaków (16-bitowe Unicode) i char32_t
(32-bitowe Unicode):
auto s3 = u"hello"; // const char16_t*
auto s4 = U"hello"; // const char32_t*
Nieprzetworzone literały ciągu (C++11)
Nieprzetworzone literały ciągu to tablica o wartości null — dowolnego typu znaku — zawierająca dowolny znak graficzny, w tym podwójny cudzysłów (), ukośnik odwrotny ("
\
) lub znak nowego wiersza. Nieprzetworzone literały ciągów są często używane w wyrażeniach regularnych korzystających z klas znaków oraz w ciągach HTML i ciągach XML. Aby zapoznać się z przykładami, zobacz następujący artykuł: FAQ Bjarne Stroustrupa o C++11.
// 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)";
Ogranicznik to sekwencja zdefiniowana przez użytkownika zawierająca maksymalnie 16 znaków, która bezpośrednio poprzedza nawias otwierający nieprzetworzonego literału ciągu i natychmiast następuje po nawiasie zamykającym. Na przykład, w R"abc(Hello"\()abc"
sekwencja ogranicznika to abc
, a zawartość ciągu to Hello"\(
. Ogranicznik umożliwia uściślanie nieprzetworzonych ciągów zawierających znaki podwójnego cudzysłowu i nawiasy. Ten literał ciągu powoduje błąd kompilatora:
// meant to represent the string: )"
const char* bad_parens = R"()")"; // error C2059
Ale ogranicznik rozwiązuje to:
const char* good_parens = R"xyz()")xyz";
Możesz skonstruować literał surowego ciągu, który zawiera nową linię (a nie znak ucieczki) w źródle.
// represents the string: hello
//goodbye
const wchar_t* newline = LR"(hello
goodbye)";
std::string literały (C++14)
std::string
literały to implementacje standardowej biblioteki literałów zdefiniowanych przez użytkownika (zobacz poniżej), które są reprezentowane jako "xyz"s
(z sufiksem s
). Tego rodzaju literał łańcucha tworzy tymczasowy obiekt typu std::string
, std::wstring
, std::u32string
lub std::u16string
, w zależności od określonego prefiksu. Gdy nie jest używany żaden prefiks, jak pokazano powyżej, tworzony jest std::string
.
L"xyz"s
tworzy element std::wstring
.
u"xyz"s
zwraca std::u16string, a U"xyz"s
zwraca 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 };
Sufiks s
może być również używany w surowych literałach ciągów.
u32string str6{ UR"(She said "hello.")"s };
std::string
literały są definiowane w przestrzeni nazw std::literals::string_literals
w pliku nagłówka <string>. Ponieważ std::literals::string_literals
i std::literals
są obie zadeklarowane jako wbudowane przestrzenie nazw, std::literals::string_literals
jest automatycznie traktowany, tak jakby należał bezpośrednio do przestrzeni nazw std
.
Rozmiar literałów ciągu
W przypadku ciągów ANSI char*
i innych kodowań jednobajtowych (z wyjątkiem UTF-8) rozmiar literału tekstowego (w bajtach) to liczba znaków powiększona o 1, aby uwzględnić znak zerowy końca ciągu. W przypadku wszystkich innych typów ciągów rozmiar nie jest ściśle powiązany z liczbą znaków. Kodowanie UTF-8 używa maksymalnie czterech char
elementów do kodowania niektórych jednostek kodu, a char16_t
lub wchar_t
jako UTF-16 może używać dwóch elementów (w sumie czterech bajtów) do kodowania pojedynczej jednostki kodu. W tym przykładzie pokazano rozmiar literału szerokiego ciągu w bajtach:
const wchar_t* str = L"Hello!";
const size_t byteSize = (wcslen(str) + 1) * sizeof(wchar_t);
Zwróć uwagę, że strlen()
i wcslen()
nie uwzględniają rozmiaru kończącego znaku null, którego rozmiar jest równy rozmiarowi elementu typu ciągu: jeden bajt w ciągach char*
lub char8_t*
, dwa bajty w ciągach wchar_t*
lub char16_t*
, a cztery bajty w ciągach char32_t*
.
Maksymalna długość literału tekstowego po konkatenacji.
- Visual Studio przed wersją 17.0 z 2022 roku: maksymalna długość literału ciągu po konkatenacji wynosi 65 535 bajtów. Dotyczy to zarówno wąskich, jak i szerokich literałów ciągów.
- Od wersji 17.0 programu Visual Studio 2022: maksymalna długość literału ciągu po łączeniu jest ograniczona tylko przez dostępną pamięć. Jednak limit rozmiaru przed łączeniem wynosi nadal 16 384 bajtów
Modyfikowanie literałów ciągu
Ponieważ literały ciągu (z wyłączeniem std::string
literałów) są stałymi, próba ich zmodyfikowania — na przykład str[2] = 'A'
— powoduje błąd kompilatora.
specyficzne dla firmy Microsoft
W języku Microsoft C++można użyć literału ciągu, aby zainicjować wskaźnik na wartość inną niż const char
lub wchar_t
. To inicjowanie inne niż const jest dozwolone w kodzie C99, ale jest przestarzałe w języku C++98 i usunięte w języku C++11. Próba zmodyfikowania ciągu powoduje naruszenie dostępu, jak w tym przykładzie:
wchar_t* str = L"hello";
str[2] = L'a'; // run-time error: access violation
Kompilator może emitować błąd, gdy literał ciągu jest konwertowany na wskaźnik znaków inny niż const, jeśli ustawisz opcję kompilatora /Zc:strictStrings
(Wyłącz konwersję typu literału ciągu). Zalecamy używanie kodu przenośnego zgodnego ze standardami. Dobrym rozwiązaniem jest również użycie słowa kluczowego auto
do deklarowania inicjatorów literałów ciągu, ponieważ jest rozpoznawany jako poprawny typ (const). Na przykład ten przykład kodu przechwytuje próbę zapisania do literału ciągu w czasie kompilacji:
auto str = L"hello";
str[2] = L'a'; // C3892: you cannot assign to a variable that is const.
W niektórych przypadkach identyczne literały ciągów mogą być łączone w celu zaoszczędzenia miejsca w pliku wykonywalnym. W procesie współdzielenia literałów ciągu, kompilator powoduje, że wszystkie odwołania do określonego literału ciągu wskazują na to samo miejsce w pamięci, zamiast aby każde odwołanie wskazywało na oddzielne wystąpienie tego literału. Aby włączyć pooling ciągów, użyj opcji kompilatora /GF
.
Sekcja specyficzna dla firmy Microsoft kończy się tutaj.
Łączenie sąsiednich literałów ciągu
Sąsiadujące szerokie lub wąskie literały ciągów są łączone. Ta deklaracja:
char str[] = "12" "34";
jest identyczna z tą deklaracją:
char atr[] = "1234";
i do tej deklaracji:
char atr[] = "12\
34";
Używanie osadzonych kodów ucieczki szesnastkowych w celu określenia literałów ciągów może spowodować nieoczekiwane wyniki. Poniższy przykład próbuje utworzyć literał ciągu zawierający znak ASCII 5, a następnie znaki f, i, v i e:
"\x05five"
Rzeczywisty wynik to szesnastkowy 5F, który jest kodem ASCII dla podkreślnika, a następnie występują znaki i, v i e. Aby uzyskać prawidłowy wynik, możesz użyć jednej z następujących sekwencji ucieczki:
"\005five" // Use octal literal.
"\x05" "five" // Use string splicing.
std::string
literały (i powiązane std::u8string
, std::u16string
i std::u32string
) mogą być łączone z operatorem +
zdefiniowanym dla basic_string
typów. Można je również łączyć w taki sam sposób, jak sąsiadujące literały ciągu. W obu przypadkach kodowanie ciągów i sufiks muszą być zgodne:
auto x1 = "hello" " " " world"; // OK
auto x2 = U"hello" " " L"world"; // C2308: disagree on prefix
auto x3 = u8"hello" " "s u8"world"z; // C3688, disagree on suffixes
Literały ciągu z uniwersalnymi nazwami znaków
Literały ciągu natywnego (nieprzetworzonego) mogą używać uniwersalnych nazw znaków do reprezentowania dowolnego znaku, o ile nazwa znaku uniwersalnego może być zakodowana jako co najmniej jeden znak w typie ciągu. Na przykład nazwa znaku uniwersalnego reprezentująca znak rozszerzony nie może być zakodowana w wąskim ciągu przy użyciu strony kodowej ANSI, ale może być zakodowana w wąskich ciągach na niektórych stronach kodu wielobajtowego lub w ciągach UTF-8 lub w szerokim ciągu. W języku C++11 obsługa Unicode jest rozszerzona o typy ciągów char16_t*
i char32_t*
, a w C++20 rozszerzona o typ char8_t
:
// ASCII smiling face
const char* s1 = ":-)";
// UTF-16 (on Windows) encoded WINKING FACE (U+1F609)
const wchar_t* s2 = L"😉 = \U0001F609 is ;-)";
// UTF-8 encoded SMILING FACE WITH HALO (U+1F607)
const char* s3a = u8"😇 = \U0001F607 is O:-)"; // Before C++20
const char8_t* s3b = u8"😇 = \U0001F607 is O:-)"; // C++20
// UTF-16 encoded SMILING FACE WITH OPEN MOUTH (U+1F603)
const char16_t* s4 = u"😃 = \U0001F603 is :-D";
// UTF-32 encoded SMILING FACE WITH SUNGLASSES (U+1F60E)
const char32_t* s5 = U"😎 = \U0001F60E is B-)";
Zobacz też
Zestawy znaków
Literały liczbowe, logiczne i wskaźnikowe
Literały zdefiniowane przez użytkownika