Как получить код символа в си
Перейти к содержимому

Как получить код символа в си

  • автор:

Как получить код символа в си

Стандартная библиотека С++ также предоставляет ряд встроенных функций для работы с символами. В основном они связанны с проверкой символов:

  • isupper(c) : проверяет, является ли c заглавной буквой, по умолчанию от «A» до «Z»
  • islower(c) : проверяет, является ли c буквой нижнего регистра, по умолчанию от ‘a’ до ‘z’
  • isalpha(c) : проверяет, является ли c алфавитным символом
  • isdigit(c) : проверяет, является ли c цифрой от ‘0’ до ‘9’
  • isxdigit(c) : проверяет, является ли c шестнадцатеричной цифрой, от ‘0’ до ‘9’, от ‘a’ до ‘f’ или от ‘A’ до ‘F’
  • isalnum(c) : проверяет, является ли c алфавитно-цифровым символом; аналогично isisalpha(c) || isdigit(c)
  • isspace(c) : проверяет, является ли c пробелом (‘ ‘), символом перевода строки (‘\n’), возвратом каретки (‘\r’), перевод страницы (‘\f’), горизонтальная (‘\t’) или вертикальная (‘\v’) табуляция
  • isblank(c) : проверяет, является ли c пробелом (‘ ‘) или символом табуляция (‘\t’)
  • ispunct(c) : проверяет, является ли c символом пунктуации (один из следующих: _ < >[ ] # ( ) < >% : ; ? * + — / ^ & | ~ ! » brush:cpp;»> #include int main() < unsigned char letter ; if (std::isupper(letter)) std::cout

    Данные функции очень часто применяются при обработке строк. Рассмотрим прстейшую задачу — нам надо извлечь из некоторого текста (например, из строки «Phone number: +1(234)456-78-90» ) номер телефона:

    #include #include int main() < std::string text ; std::string phone; // строка для хранения номера for(unsigned i<>; i < text.length(); i++) < // проверяем, является ли символ цифрой if(std::isdigit(text[i])) < // добавляем в строку номера телефона phone += text[i]; >> std::cout 

    Здесь проходим по всем символам текста и, если символ представляет цифру, то заносим его в строку phone. Другая задача — нам надо сравнить две строки вне зависимости от регистра. С одной стороны, мы могли бы использовать простую операцию сравнения ==, которая также может сравнивать строки. Но если мы попытаемся сравнить две строки, в которых хотя бы один символ отличается по регистру, то они будут не равны:

    #include #include int main() < std::string word1 ; word1 = "hello"; std::string word2 ; if(word1 == word2) < std::cout else < std::cout >

    Результат данной программы:

    strings are not equal

    Чтобы организовать сравнение без учета регистра, мы могли бы переводить символы в верхний или нижний регистр и сравнивать их:

    #include #include int main() < std::string word1 ; std::string word2 ; bool is_equal; // равны ли строки if(word1.length() != word2.length()) < is_equal = false; >else < // сравниваем все символы for(unsigned i<>; i < word1.length(); i++) < // переводим символы в нижний регистр и сравниваем if(std::tolower(word1[i]) != std::tolower(word2[i])) < // если символы не равны, сбрасываем флаг равенства is_equal = false; break; // выходим из цикла >> > if(is_equal) < std::cout else < std::cout >

    В данном случае сначала сравниваем длину строк, так как если длины не равны, то сами строки тоже не равны. Далее в цикле проходим по всем символам обоих строк, переводим их в нижний регистр и сравниваем. Если хотя бы одна пара соответствующих символов не равна, то сбрасываем флаг равенства is_equal в false и выходим из цикла, поскольку строки в этом случае будут уже не равны, и дальше нет смысла сравнивать символы. Результат данной программы:

    HELLO and hello are equal

    Как получить код символа в си

    При запуске программы на Си автоматически открываются ряд потоков, основными из которых являются следующие:

    • Стандартный поток ввода stdin
    • Стандартный поток вывода stdout
    • Стандартный поток вывода сообщений об ошибках stderr

    Стандартный поток ввода stdin по умолчанию соответствует клавиатуре, а потоки stdout и stderr — экрану монитора.

    Для управления вводом-выводом с помощью этих потоков используются ряд функций:

    • getchar() : ввод с клавиатуры одного символа
    • putchar() : вывод на консоль одного символа
    • fgets() : ввод одной строки
    • puts() / fputs() : вывод одной строки на консоль
    • scanf() : ввод с консоли с форматированием данных
    • sscanf() : ввод с из строки с форматированием данных
    • printf() : вывод с форматированием данных

    Функции printf и scanf уже рассматривались ранее, поэтому посмотрим, как применять остальные функции.

    Ввод и вывод символов

    Для ввода и вывода символа применяются функции getchar() и putchar() . Но следует сказать, что на самом деле они полноценными функциями не являются, а определены как макросы в заголовочном файле stdio.h :

    #define getchar() getc(stdin) #define putchar(c) putc((c), stdout)
    Вывод символа

    Для вывода отдельного символа на консоль предназначена функция putchar() со следующим прототипом:

    int putchar(int c);

    Выводимый символ в виде числового кода передается в putchar в качестве параметра, он же возвращается функцией.

    #include int main(void) < char c = 'A'; putchar(c); // Выводим символ A >
    Ввод символа

    Для ввода одного символа с клавиатуры применяется функция getchar() , которая имеет следующий прототип:

    int getchar(void);

    В качестве результата функция возвращает числовой код введенного символа.

    При использовании функции getchar следует учитывать, что при печати текста посредством клавиатуры в буфер операционной системы заносятся коды печатаемых символов, а сами символы отображаются на экране. Поучение программой введенного символа из буфера производится с помощью нажатия клавиши Enter.

    И если буфер операционной системы не пуст, то при вызове функции getc() она получает очередной символ из буфера. Если же буфер пуст, то происходит чтение байта из потока ввода с помощью системной функции, название которой зависит от операционной системы.

    При этом при нажатии клавиши Enter, в буфер также помещается код этой клавиши. То есть если мы введем один символ и нажмем на Enter, в буфере окажутся два числовых кода — введенного символа и клавиши Enter. И это надо учитывать при работе с функцией getchar. В частости, рассмотрим простой, но показательный пример:

    #include int main(void) < printf("1"); getchar(); // ожидание ввода символа printf("2"); getchar(); // ожидание ввода символа printf("3"); return 0; >

    Сначала на экран выводится цифра 1, после чего функция getchar ожидает ввода символа. Если после ввода символа мы нажмем Enter, то в буфер будет помещены два числовых кода — введеного символа и клавиши Enter. Поэтому при втором вызове getchar эта функция считывает байт из буфера — то есть числовой код клавиши Enter.

    Например, введем при первом вызове функции getchar символ «a», а затем Enter:

    1a 23

    Но если при каждом вызове getchar мы будем только нажимать клавишу Enter, тогда в буфер будет заноситься только код этой клавиши, и соответственно программа будет работать, как и ожидалось:

    1 2 3

    Применим функции getchar и putchar для ввода и вывода символов с клавиатуры:

    #include int main(void) < int c; while((c=getchar())!=EOF) < putchar(c); >return 0; >

    Функция getchar() считывает числовой код символа, который потом выводится в функции putchar() . Для вывода из программы необходимо ввести комбинацию клавиш Ctrl+C.

    Ввод и вывод строк

    Вывод строк и puts

    Для вывода одной строки на консоль предназначена функция puts() со следующим прототипом:

    int putchar(char *s);

    В качестве параметра передается указатель на строку, а возвращаемым результатом функции является последний выведенный символ.

    При этом функция puts() будет выводить символы переданной строки, пока не дойдет до нулевого символа ‘\0’. Если же выводимый массив символов не содержит этого символа, то результат программы неопределен. Например:

    #include int main(void) < puts("Hello World"); // выводим строковый литерал char* name = "Hello Metanit.com"; puts(name); // выводим значение переменной return 0; >
    Hello World Hello Metanit.com
    Вывод строк и fputs

    Функция fputs() также записывает в поток вывода строку, то есть набор символов, который завершается символом ‘\0’. При записи строки нулевой символ ‘\0’ не записывается. Она имеет следующий прототип:

    int fputs(const char *s, FILE *stream);

    Первый параметр функции — записываемая строка, а второй — указатель на поток вывода. В качестве результата функция возвращает неотрицательное целое число. При ошибках в процессе записи возвращается значение EOF .

    Применим функцию для записи в стандартный поток вывода, то есть на консоль. В этом случае в качестве второго параметра надо передать значение stdout :

    #include int main(void)

    Ввод строк и fgets

    Для ввода строки с клавиатуры применяется функция fgets() , которая имеет следующий прототип:

    char *fgets(char *str, int count, FILE *stream);
    • char *str : строка, в которую производится считывание.
    • int count : сколько символов необходимо считывать.
    • FILE *stream : файловый поток, из которого производится считывание. В качестве потока ввода может выступать и консольный ввод.

    Функция fgets() прекращает считывание, когда пользователь нажимает клавишу ENTER, то есть когда в поток добавляется символ перевода строки.

    Рассмотрим считывание строки с консоли. Для этого в качестве третьего параметра в функцию передается значение stdin :

    #include #define MAX 15 int main(void)

    Здесь функция fgets считывает не более 15 символов в строку name, а В реальности функция предложит ввести 14 символов, так как последний символ зарезервирован для нулевого символа ‘\0’. Если будет введено больше символов, то fgets все равно считает не более 15 символов. Таким образом функция позволяет проверить количество считываемых символов и поэтому считается безопасной.

    Пример работы программы:

    Enter name: Tom Smith Your name: Tom Smith

    Стоит отметить, что функция fgets() возвращает указатель char * — указатель на буфер, в который считаны данные. В реальности это тот же самый буфер, который передавался в качестве первого параметра, то есть в примере выше — это массив name. Однако этот результат может нам пригодится для проверки успешности выполнения функции — если считывание прошло неудачно, то функция возвращает NULL :

    #include #define MAX 15 int main(void) < char name[MAX]; printf("Enter name: "); if(fgets(name, MAX, stdin) != NULL) // if(fgets(name, MAX, stdin)) - можно сократить < printf("Your name: %s\n", name); >else < printf("Critical Error. "); >return 0; >

    Для эмуляции ошибки можно передать в функцию вторым параметром число 0.

    fgets и scanf

    При использовании функции fgets() после функции scanf() мы можем столкнуться с некорректным вводом:

    #include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >

    В данном случае сначала с помощью функции scanf() считываем число в переменную age. После этого считываем имя — строку с помощью функции fgets() в переменную name. Но посмотрим, какой будет результат работы программы:

    Input age: 39 Input name: Age: 39Name:

    В данном случае мы видим, что ввод имени с помощью fgets вроде как пропускается. По крайней мере мы не можем ввести имя, а программа сразу же выводит результат.

    Все дело в том, что функция scanf() считывает именно то, что ей предписано — число в виде переменной типа int. Все остальные символы остаются в буфере, в который предварительно попадают введенные с клавиатуры символы. Так, после ввода возраста мы нажимаем на клавишу Enter, и в буфер попадает символ «\n», то есть перевод строки. И fgets считывает этот символ из буфера, после чего ввод имени завершается. Очевидно, это не то поведение, на которое мы рассчитывали.

    Чтобы исправить ситуацию, мы можем использовать различные хаки. Рассмотрим пару из них. Все они сводятся к тому, чтобы вынуть из буфера этот символ перевода строки.

    Первый способ — считывание символа с помощью вызова scanf(«%*c») :

    #include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); scanf("%*c"); // вытаскиваем символ из буфера // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >

    Второй способ — мы можем считать символ с помощью getchar() :

    #include #define N 32 int main(void) < int age; char name[N]; // считываем возраст в переменную age printf("Input age: "); scanf("%d", &age); getchar(); // вытаскиваем символ из буфера // считываем строку в переменну. name printf("Input name: "); fgets(name, N, stdin); // проверяем ввод printf("Age: %d\n", age); printf("Name: %s\n", name); >

    Результат работы программы:

    Input age: 39 Input name: Tom Age: 39 Name: Tom

    Пример кода на Cи

    Программирование на Си — это азбука, которую необходимо овладеть, чтобы стать настоящим разработчиком. Если вы только начинаете свой путь в мире программирования или хотите освоить новый язык программирования, Си — отличный выбор. Этот мощный язык уже давно заслужил свою популярность благодаря своей скорости и эффективности. Программы на Си могут быть использованы во множестве различных областей: от встроенных систем до научных исследований.

    В этой статье мы рассмотрим основы написания кода на Си с примерами и объяснениями. Начнем с простых концепций, таких как переменные и типы данных, и постепенно перейдем к более сложным темам, таким как условные операторы и циклы. Вы узнаете, как объявлять переменные, присваивать им значения, выполнять арифметические операции и многое другое.

    Мы также рассмотрим примеры кода на Си, чтобы продемонстрировать практическое применение концепций. Вы узнаете, как написать простые программы, такие как калькулятор или программу для вычисления факториала числа. Каждый пример будет сопровождаться пояснениями, чтобы помочь вам лучше понять, как работает код.

    Основы языка программирования Си

    Язык программирования Си был создан в 1972 году и с тех пор стал одним из самых популярных языков программирования. Он известен своей простотой и эффективностью, а также используется для разработки операционных систем, драйверов, встроенных систем и других программ, где требуется максимальная производительность.

    Структура программы на Си

    Программы на Си состоят из функций, которые выполняют определенные действия. Главная функция в программе на Си имеет следующий вид:

    int main()
    // тело функции
    return 0;
    >

    Основное тело программы на Си располагается внутри функции main() . При запуске программы первым делом выполняется код внутри этой функции.

    Переменные и типы данных

    Переменные в Си служат для хранения данных и имеют свой тип. В Си существует несколько основных типов данных:

    • int — для хранения целых чисел
    • float — для хранения чисел с плавающей точкой
    • char — для хранения символов
    • double — для хранения чисел с плавающей точкой двойной точности

    Декларация переменной на Си выглядит следующим образом:

    В данном примере создается переменная age типа int для хранения возраста.

    Операторы и выражения

    Язык Си предоставляет множество операторов, с помощью которых можно выполнять различные действия. Некоторые из основных операторов:

    • = — присваивание значения переменной
    • + — сложение двух значений
    • — вычитание одного значения из другого
    • * — умножение двух значений
    • / — деление одного значения на другое
    • % — остаток от деления

    Смотрите также: Пагинация в PHP: руководство для начинающих

    Выражение на Си — это комбинация операторов и операндов (переменных, констант и функций).

    В данном примере выполняется сложение чисел 5 и 3, результат которого присваивается переменной sum .

    Это лишь небольшая часть основ языка программирования Си. Изучение Си позволяет разработчикам создавать эффективные программы, манипулировать памятью и работать непосредственно с аппаратными ресурсами компьютера.

    Структура программы на Си

    Каждая программа на языке Си состоит из набора функций, а сама программа начинается с функции main() . Внутри функции main() содержатся инструкции, которые будут выполнены при запуске программы.

    Программа на Си имеет следующую общую структуру:

    Директивы препроцессора Здесь задаются настройки компиляции программы и импортируются необходимые библиотеки.
    Объявление глобальных переменных Это место для объявления переменных, которые будут использоваться внутри функций.
    Объявление функций Здесь объявляются все функции, которые будут использоваться в программе. Каждая функция должна быть объявлена до её первого использования.
    Функция main() Это точка входа в программу. Здесь содержатся инструкции, которые будут выполнены при запуске программы.
    Остальные функции Если в программе есть другие функции, они объявляются и реализуются после функции main() .

    Пример структуры программы на Си:

    #include /* Объявление глобальных переменных */ int globalVariable = 5; /* Объявление функций */ void printMessage() < printf("Привет, мир! "); >/* Функция main() */ int main() < /* Инструкции, которые будут выполнены при запуске программы */ printMessage(); return 0; >/* Остальные функции */ // Здесь можно объявить и реализовать другие функции 

    Переменные и типы данных в Си

    В языке программирования Си переменные используются для хранения данных. Каждая переменная имеет тип данных, который определяет, какие значения и операции доступны для этой переменной.

    В Си существует несколько основных типов данных:

    Целочисленные типы (int)

    Целочисленные типы данных предназначены для хранения целых чисел. В Си доступны различные целочисленные типы, такие как int , short int и long int . Различные типы имеют разные размеры и могут хранить различные диапазоны значений.

    Вещественные типы (float и double)

    Вещественные типы данных используются для хранения чисел с плавающей запятой. В Си доступны два основных типа вещественных чисел: float и double . Тип float обычно используется для хранения чисел с одинарной точностью, а тип double — для хранения чисел с двойной точностью.

    Смотрите также: Инструмент Nmap в операционной системе Kali Linux

    Символьный тип (char)

    Символьный тип данных char используется для хранения отдельных символов. Каждый символ представляется в Си как целое число, которое соответствует его коду ASCII.

    Логический тип (bool)

    Логический тип данных bool может принимать только два значения: true (истина) и false (ложь). Логический тип данных обычно используется для выполнения условных операций и проверки логических выражений.

    Примеры объявления переменных:

    int a; // объявление переменной типа int float b; // объявление переменной типа float double c; // объявление переменной типа double char d; // объявление переменной типа char bool e; // объявление переменной типа bool 

    После объявления переменной можно присвоить ей значение:

    int a = 10; // присвоение значения 10 переменной a float b = 3.14; // присвоение значения 3.14 переменной b double c = 2.71828; // присвоение значения 2.71828 переменной c char d = 'A'; // присвоение значения 'A' переменной d bool e = true; // присвоение значения true переменной e 

    Также можно изменить значение переменной путем присваивания нового значения:

    a = 20; // изменение значения переменной a на 20 b = 2.718; // изменение значения переменной b на 2.718 c = 3.14; // изменение значения переменной c на 3.14 d = 'B'; // изменение значения переменной d на 'B' e = false; // изменение значения переменной e на false 

    В Си также есть возможность преобразования типов данных с помощью явного приведения типов. Например:

    int a = 5; // объявление и инициализация переменной типа int double b = (double) a; // приведение значения переменной a к типу double 

    В данном примере значение переменной a , которое имеет тип int , приводится к типу double и присваивается переменной b .

    Управляющие конструкции на Си

    Язык программирования Си предоставляет различные управляющие конструкции, которые позволяют контролировать поток исполнения программы. В этом разделе мы рассмотрим наиболее распространенные управляющие конструкции на Си.

    Условные выражения if-else

    Условная конструкция if-else используется для выполнения определенных действий в зависимости от истинности или ложности некоторого условия. Вот пример использования условной конструкции:

     if (условие) < // блок кода, который выполнится, если условие истинно >else < // блок кода, который выполнится, если условие ложно >

    В этом примере, если условие истинно, будет выполнен первый блок кода, иначе будет выполнен второй блок кода.

    Циклы while и do-while

    Циклы while и do-while используются для повторения определенного блока кода, пока некоторое условие истинно. Вот пример использования цикла while:

     while (условие) < // блок кода, который будет повторяться, пока условие истинно >

    В этом примере, блок кода будет повторяться, пока условие истинно.

    Смотрите также: Программирование на Учи.ру

    Цикл do-while похож на цикл while, но он всегда выполняет блок кода хотя бы один раз, а затем проверяет условие. Вот пример использования цикла do-while:

     do < // блок кода, который будет повторяться, пока условие истинно >while (условие); 

    В этом примере, блок кода будет выполнен хотя бы один раз, а затем будет повторяться, пока условие истинно.

    Цикл for

    Цикл for предоставляет более компактную форму цикла, позволяя задать инициализацию, условие и шаг в одной строке. Вот пример использования цикла for:

     for (инициализация; условие; шаг) < // блок кода, который будет повторяться, пока условие истинно >

    В этом примере, сначала выполняется инициализация, затем проверяется условие, и если оно истинно, выполняется блок кода. После каждой итерации, выполняется шаг и затем снова проверяется условие.

    Операторы break и continue

    Оператор break используется для немедленного выхода из текущего цикла или переключения на следующую итерацию цикла. Вот пример использования оператора break:

     for (int i = 0; i < 10; i++) < if (i == 5) < break; // выход из цикла, если значение i равно 5 >> 

    В этом примере, когда значение переменной i становится равным 5, цикл прерывается и программа продолжает выполнение сразу после цикла.

    Оператор continue используется для пропуска текущей итерации цикла и перехода к следующей итерации. Вот пример использования оператора continue:

     for (int i = 0; i < 10; i++) < if (i == 5) < continue; // пропуск текущей итерации, если значение i равно 5 >> 

    В этом примере, когда значение переменной i становится равным 5, текущая итерация пропускается, и программа переходит к следующей итерации.

    Это лишь некоторые из управляющих конструкций, доступных на языке Си. Их понимание и правильное использование позволяют оптимизировать и контролировать флоу исполнения программы, обеспечивая ее гибкость и эффективность.

    Вопрос-ответ:

    Какие основные особенности языка программирования Си?

    Язык программирования Си является структурным и императивным, имеет низкоуровневые возможности и широко используется для написания операционных систем и встраиваемого ПО. Он обладает простым и лаконичным синтаксисом, позволяющим писать эффективный и быстрый код.

    Строковые и символьные литералы (C++)

    В C++ поддерживаются различные типы строк и символов, а также доступны различные способы выражения значений литералов каждого из этих типов. В исходном коде содержимое символьных и строковых литералов выражается с помощью кодировки. Универсальные имена символов и escape-символы позволяют представить любую строку, используя только основную кодировку исходного кода. Необработанные строковые литералы позволяют не использовать escape-символы и могут применяться для выражения всех типов строковых литералов. Вы также можете создавать std::string литералы, не выполняя дополнительные действия по созданию или преобразованию.

    #include 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 >

    Строковые литералы не могут иметь префикс или u8 L , u и U префиксы для обозначения узкого символа (однобайтового или многобайтового), UTF-8, широкий символ (UCS-2 или UTF-16), кодировки UTF-16 и UTF-32 соответственно. Необработанный строковый литерал может иметь R , u8R и LR uR UR префиксы для необработанных эквивалентов этих кодировок. Чтобы создать временные или статические std::string значения, можно использовать строковые литералы или необработанные строковые литералы с суффиксом s . Дополнительные сведения см. в разделе «Строковые литералы » ниже. Дополнительные сведения о базовом наборе исходных символов, универсальных именах символов и использовании символов из расширенных кодовых страниц в исходном коде см. в разделе «Наборы символов».

    Символьные литералы

    Символьный литерал состоит из символьной константы. Он представлен символом, окруженным одними кавычками. Существует пять типов символьных литерала:

    • Обычные символьные литералы типа char , например ‘a’
    • Символьные литералы UTF-8 типа char ( char8_t в C++20), например u8’a’
    • Расширенные символьные литералы типа wchar_t , например L’a’ .
    • Символьные литералы типа char16_t UTF-16, например u’a’
    • Символьные литералы типа char32_t UTF-32, например U’a’

    Символ, используемый для литерала символов, может быть любым символом, за исключением зарезервированных символов обратной косой черты ( \ ), одной кавычки ( ) или новой строки. Зарезервированные символы можно указывать с помощью escape-последовательности. Символы можно указывать с помощью универсальных имен символов, при условии что тип является достаточно крупным для размещения символа.

    Кодировка

    Литералы символов кодируются по-разному на основе префикса.

    • Литерал символов без префикса — обычный символьный литерал. Значение обычного символьного литерала, содержащего один символ, escape-последовательность или универсальное имя символа, которое может быть представлено в наборе символов выполнения, имеет значение, равное числовому значению его кодировки в наборе символов выполнения. Обычный литерал символов, содержащий несколько символов, escape-последовательность или универсальное имя символов, является многофакторным литералом. Многофакторный литерал или обычный символьный литерал, который не может быть представлен в наборе символов выполнения, имеет тип int , и его значение определяется реализацией. Сведения о MSVC см. в следующем разделе майкрософт.
    • Символьный литерал, начинающийся с L префикса, — это символьный литерал. Значение символьного литерала, содержащего один символ, escape-последовательность или универсальное имя символов, имеет значение, равное числовому значению его кодировки в наборе символов, если литерал символов не имеет представления в наборе расширенных символов выполнения, в этом случае значение определяется реализацией. Значение расширенных символьных литералов, содержащих несколько символов, escape-последовательностей или универсальных имен символов, определяется реализацией. Сведения о MSVC см. в следующем разделе майкрософт.
    • Символьный литерал, начинающийся с u8 префикса, — это символьный литерал UTF-8. Значение символьного литерала UTF-8, содержащего один символ, escape-последовательность или универсальное имя символов, имеет значение, равное значению точки кода ISO 10646, если оно может быть представлено одним блоком кода UTF-8 (соответствующим блоку элементов управления C0 и Basic Latin Юникод). Если значение не может быть представлено одним блоком кода UTF-8, программа не сформирована. Символьный литерал UTF-8, содержащий несколько символов, escape-последовательность или универсальное имя символов, является неправильно сформированным.
    • Символьный литерал, начинающийся с u префикса, является литералом символов UTF-16. Значение символьного литерала UTF-16, содержащего один символ, escape-последовательность или универсальное имя символов, имеет значение, равное значению точки кода ISO 10646, если оно может быть представлено одной единицей кода UTF-16 (соответствующей базовой многоязычной плоскости). Если значение не может быть представлено одним блоком кода UTF-16, программа не сформирована. Литерал символа UTF-16, содержащий несколько символов, escape-последовательность или универсальное имя символов, является неправильно сформированным.
    • Символьный литерал, начинающийся с U префикса, — это символьный литерал UTF-32. Значение символьного литерала UTF-32, содержащего один символ, escape-последовательность или универсальное имя символов, имеет значение, равное значению точки кода ISO 10646. Символьный литерал UTF-32, содержащий несколько символов, escape-последовательность или универсальное имя символов, является неправильно сформированным.

    Escape-последовательности

    Существует три вида escape-последовательностей: простая, восьмеричная и шестнадцатеричная. Escape-последовательности могут быть любым из следующих значений:

    Значение escape-последовательность
    новая строка \n
    обратная косая черта \\
    горизонтальная табуляция \t
    вопросительный знак ? Или\?
    вертикальная табуляция \v
    одинарная кавычка \’
    BACKSPACE \b
    двойная кавычка
    Возврат каретки \r
    нуль-символ \0
    Смена страницы \f
    восьмеричный \ooo
    оповещение (колокольчик) \a
    шестнадцатеричный \xhhh

    Восьмеричная escape-последовательность — это обратная косая черта, за которой следует последовательность из одной до трех восьмеричных цифр. Восьмеричная escape-последовательность завершается на первом символе, который не является восьмеричной цифрой, если обнаружена раньше, чем третья цифра. Максимально возможное восьмеричное значение . \377

    Шестнадцатеричная escape-последовательность — это обратная косая черта, за которой следует символ x , за которой следует последовательность одной или нескольких шестнадцатеричных цифр. Начальные нули пропускаются. В обычном или префиксном литерале символов u8 самое высокое шестнадцатеричное значение 0xFF. В расширенном символьном литерале с префиксом L или u максимальное шестнадцатеричное значение — 0xFFFF. В расширенном символьном литерале с префиксом U максимальное шестнадцатеричное значение — 0xFFFFFFFF.

    В этом примере кода показаны некоторые примеры экранированных символов с помощью обычных литералов символов. Тот же синтаксис escape-последовательности действителен для других типов литеральных символов.

    #include using namespace std; int main() < char newline = '\n'; char tab = '\t'; char backspace = '\b'; char backslash = '\\'; char nullChar = '\0'; cout /* Output: Newline character: ending Tab character: ending Backspace character:ending Backslash character: \ending Null character: ending */ 

    Символ обратной косой черты ( \ ) — это символ продолжения строки, когда он помещается в конце строки. Если символ обратной косой черты требуется использовать как символьный литерал, необходимо ввести две косые черты подряд ( \\ ). Дополнительные сведения о символе продолжения строки см. в разделе Phases of Translation.

    Только для систем Майкрософт

    Чтобы создать значение из узкого многофакторного литерала, компилятор преобразует последовательность символов или символов между одними кавычками в 8-разрядные значения в 32-разрядное целое число. Несколько символов в литерале заполняют соответствующие байты по мере необходимости от высокого до низкого порядка. Затем компилятор преобразует целое число в тип назначения, следуя обычным правилам. Например, чтобы создать char значение, компилятор принимает байт низкого порядка. Для создания значения wchar_t или char16_t компилятор принимает младшее слово. Компилятор выдает предупреждение о том, что результат усекается, если какие-либо биты заданы выше назначенного байта или слова.

    char c0 = 'abcd'; // C4305, C4309, truncates to 'd' wchar_t w0 = 'abcd'; // C4305, C4309, truncates to '\x6364' int i0 = 'abcd'; // 0x61626364 

    Восьмеричная escape-последовательность, которая, как представляется, содержит более трех цифр, рассматривается как 3-разрядная октальная последовательность, за которой следует последующие цифры в виде символов в многофакторном литерале, что может дать удивительные результаты. Например:

    char c1 = '\100'; // '@' char c2 = '\1000'; // C4305, C4309, truncates to '0' 

    Escape-последовательности, которые, как представляется, содержат неосьмеривые символы, оцениваются как восьмеричное последовательность до последнего октационного символа, а затем остальные символы в виде последующих символов в многохарактерном литерале. Предупреждение C4125 создается, если первый не восьмеричный символ является десятичной цифрой. Например:

    char c3 = '\009'; // '9' char c4 = '\089'; // C4305, C4309, truncates to '9' char c5 = '\qrs'; // C4129, C4305, C4309, truncates to 's' 

    Восьмеричная escape-последовательность, которая имеет более высокое значение, чем \377 вызывает ошибку C2022: value-in-decimal : слишком большой для символа.

    Последовательность escape,которая, как представляется, имеет шестнадцатеричные и не шестнадцатеричные символы, оценивается как многофакторный литерал, содержащий шестнадцатеричную последовательность escape-последовательности до последнего шестнадцатеричного символа, за которым следует не шестнадцатеричные символы. Шестнадцатеричная escape-последовательность, содержащая шестнадцатеричные цифры, приводит к ошибке компилятора C2153: "шестнадцатеричные литералы должны иметь по крайней мере одну шестнадцатеричную цифру".

    char c6 = '\x0050'; // 'P' char c7 = '\x0pqr'; // C4305, C4309, truncates to 'r' 

    Если расширенный символьный литерал, префиксированный с L несколькими диаграммами, то значение берется из первого символа, а компилятор вызывает предупреждение C4066. Последующие символы игнорируются, в отличие от поведения эквивалентного обычного многофакторного литерала.

    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 

    Раздел , посвященный майкрософт , заканчивается здесь.

    универсальные имена символов

    В символьных литералах и машинных (не являющихся необработанными) строковых литералах любой символ может быть представлен универсальным именем символа. Универсальные имена символов формируются префиксом \U , за которым следует восьмизначная кодовая точка Юникода или префикс \u , за которым следует четырехзначная точка кода Юникода. Все восемь или четыре знака, соответственно, должны присутствовать для создания корректного универсального имени символа.

    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' 
    Суррогатные пары

    Универсальные имена символов не могут кодировать значения в диапазоне суррогатных точек кода D800-DFFF. Для суррогатных пар Юникода укажите универсальное имя символа, используя \UNNNNNNNN , где NNNNNNNN — восьмизначная кодовая точка для символа. При необходимости компилятор создает суррогатную пару.

    В C++03 язык допускает только подмножество символов, представленных их универсальными именами символов, и допускает некоторые универсальные имена символов, которые фактически не представляют допустимые символы Юникода. Эта ошибка была исправлена в стандарте C++11. В C++11 в символьных и строковых литералах и идентификаторах можно использовать универсальные имена символов. Дополнительные сведения об универсальных именах символов см. в разделе Character Sets. Дополнительные сведения о Юникоде см. в статье Unicode. Дополнительные сведения о суррогатных парах см. в статье Surrogate Pairs and Supplementary Characters(Суррогатные пары и дополнительные символы).

    Строковые литералы

    Строковый литерал представляет последовательность символов, которые вместе образуют строку с завершающим нулем. Символы должны быть заключены в двойные кавычки. Существуют следующие типы строковых литералов.

    Узкие строковые литералы

    Узкий строковый литерал — это не префиксированный, разделенный двойными кавычками массив const char[n] типа, в котором n — длина массива в байтах. Обычный строковый литерал может содержать любые графические символы, за исключением двойных кавычек ( " ), обратной косой черты ( \ ) или символа новой строки. Обычный строковый литерал также может содержать перечисленные выше escape-последовательности и универсальные имена символов, которые помещаются в байте.

    const char *narrow = "abcd"; // represents the string: yes\no const char *escaped = "yes\\no"; 
    Строки в кодировке UTF-8

    Строка в кодировке UTF-8 — это префиксированный, разделенный двойным кавычками массив типа, завершаемый значением NULL, где n — длина закодированного массива const char[n] в байтах. Строковый литерал с префиксом u8 может содержать любые графические символы, за исключением двойных кавычек ( " ), обратной косой черты ( \ ) или символа новой строки. Строковый литерал с префиксом u8 может также содержать перечисленные выше escape-последовательности и любые универсальные имена символов.

    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 O:-)"; // C++20 and later const char8_t* u8str1 = u8"Hello World"; const char8_t* u8str2 = u8"\U0001F607 is O:-)"; 

    Расширенные строковые литералы

    Широкий строковый литерал — это массив констант wchar_t , префиксируемый символом null, который префиксируется " L " и содержит любой графический символ, кроме двойной кавычки ( " ), обратной косой черты ( \ ) или символа новой строки. Расширенный строковый литерал может содержать перечисленные выше escape-последовательности и любые универсальные имена символов.

    const wchar_t* wide = L"zyxw"; const wchar_t* newline = L"hello\ngoodbye"; 
    char16_t и char32_t (C++11)

    В C++11 доступны символьные типы char16_t (портативный, 16-разрядный Юникод) и char32_t (32-разрядный Юникод):

    auto s3 = u"hello"; // const char16_t* auto s4 = U"hello"; // const char32_t* 

    Необработанные строковые литералы (C++11)

    Необработанный строковый литерал — это массив, завершающий значение NULL, любой тип символа, который содержит любой графический символ, включая двойную кавычку (), обратную косую черту ( " \ ) или новый символ. Необработанные строковые литералы часто применяются в регулярных выражениях, которые используют классы символов, а также в строках HTML и XML. Примеры см. в следующей статье: Bjarne Stroustrup's FAQ on C++11(Вопросы и ответы о 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)"; 

    Разделитель — это определяемая пользователем последовательность до 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::wstring std::u32string или std::u16string в зависимости от указанного префикса. Если префикс не используется, как описано выше, создается. std::string L"xyz"s std::wstring создает объект . u"xyz"s создает std::u16string и U"xyz"s создает std::u32string.

    //#include //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 литералы определяются в пространстве std::literals::string_literals имен в файле заголовка . Поскольку std::literals::string_literals и std::literals объявляются как встроенные пространства имен, std::literals::string_literals автоматически считается напрямую принадлежащим пространству имен std .

    Размер строковых литерала

    Для строк ANSI char* и других однобайтовых кодировок (но не UTF-8), размер (в байтах) строкового литерала — это число символов плюс 1 для завершающего символа NULL. Для всех других типов строк размер не связан строго с количеством символов. UTF-8 использует до четырех char элементов для кодирования некоторых единиц кода и char16_t wchar_t в кодировке UTF-16 может использовать два элемента (в общей сложности четыре байта) для кодирования одной единицы кода. В примере ниже показан размер расширенного строкового литерала в байтах.

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

    Обратите внимание, что strlen() и wcslen() не включайте размер завершающего символа NULL, размер которого равен размеру элемента типа строки: один байт в char* строке или char8_t* строке, два байта wchar_t* или char16_t* строки и четыре байта в char32_t* строках.

    В версиях Visual Studio до Visual Studio 2022 версии 17.0 максимальная длина строкового литерала составляет 65 535 байт. Это ограничение применимо как к узким, так и к расширенным строковым литералам. В Visual Studio 2022 версии 17.0 и более поздних версиях это ограничение будет отменено, а длина строки ограничена доступными ресурсами.

    Изменение строковых литерала

    Так как строковые литералы (не включая std::string литералы) являются константами, пытаясь изменить их( например, str[2] = 'A' вызывает ошибку компилятора.

    Только для систем Майкрософт

    В Microsoft C++можно использовать строковый литерал для инициализации указателя на неконст char или wchar_t . Эта неконстантная инициализация разрешена в коде C99, но устарела в C++98 и удалена в C++11. Попытка изменить строку вызовет нарушение прав доступа, как показано в следующем примере:

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

    Компилятор может вызвать ошибку при преобразовании строкового литерала в указатель неконстного символа при настройке /Zc:strictStrings параметра компилятора (отключить преобразование строковых литеральных типов). Мы рекомендуем использовать его для переносимого кода, соответствующего стандартам. Кроме того, рекомендуется использовать auto ключевое слово для объявления строковых инициализированных указателей, так как он разрешает правильный (const) тип. В следующем примере кода перехватывается во время компиляции попытка записать в строковый литерал:

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

    В некоторых случаях идентичные строковые литералы могут быть объединены в пул для экономии места в исполняемом файле. При объединении строковых литералов в пулы компилятор делает так, что все ссылки на определенный строковый литерал указывают на одну и ту же область в памяти, вместо того чтобы каждая ссылка указывала на отдельный экземпляр строкового литерала. Чтобы включить пул строк, используйте параметр компилятора /GF .

    Раздел , посвященный майкрософт , заканчивается здесь.

    Сцепление смежных строковых литералов

    Все смежные расширенные и узкие строковые литералы соединяются. Данное объявление:

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

    идентично следующему объявлению:

    char atr[] = "1234"; 

    и следующему объявлению:

    char atr[] = "12\ 34"; 

    Использование внедренных шестнадцатеричных escape-кодов для задания строковых литералов может привести к непредвиденным результатам. В следующем примере выполняется попытка создать строковый литерал, содержащий символ ASCII 5, за которым следуют символы f, i, v и e:

    "\x05five" 

    Фактический результат (шестнадцатеричное значение 5F) является кодом ASCII для символа подчеркивания, за которым следуют символы i, v и e. Чтобы получить правильный результат, можно использовать одну из следующих escape-последовательностей:

    "\005five" // Use octal literal. "\x05" "five" // Use string splicing. 

    std::string литералы (и связанные std::u8string std::u16string , и std::u32string ) можно объединить с оператором + , определенным для basic_string типов. Эти литералы также можно соединить аналогично смежным строковым литералам. В обоих случаях кодировка строки и суффикс должны совпадать:

    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 

    Строковые литералы с универсальными именами символов

    Машинные (не являющиеся необработанными) строковые литералы могут использовать универсальные имена символов для представления любого символа, при условии что универсальные имена можно кодировать как один или несколько символов в строковом типе. Например, универсальное имя символа, представляющее расширенный символ, не может быть закодировано в узкой строке с помощью кодовой страницы 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 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-)"; 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *