Главная страница » Что является литералом строкового значения

Что является литералом строкового значения

  • автор:

Язык C: константы и литералы

Константы — фиксированные величины, которые не изменяются во время выполнения программы. Эти фиксированные величины также называются литералами.

Константы могут относиться к любому из основных типов данных, например:

  • целочисленная константа;
  • константа с плавающей точкой;
  • символьная константа;
  • строковый литерал.

Используются также перечислимые константы.

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

Целочисленные литералы

Целочисленный литерал может быть десятичной, восьмеричной или шестнадцатеричной константой. Префикс определяет основание (радикс) целочисленной константы:

  • 0x или 0X — шестнадцатеричной;
  • 0 — восьмеричной;
  • отсутствие префикса — десятичной.

Целочисленный литерал может также иметь суффикс. Он представляет собой комбинацию букв U и L, означающих целое беззнакового и длинного типа (соответственно). Суффикс может быть прописной или строчной буквой и располагаться в любом порядке.

Вот несколько примеров целочисленных литералов:

Ниже приведены другие примеры различных типов целочисленных литералов:

Литералы с плавающей точкой

Литерал с плавающей точкой состоит из целой части, десятичной точки, дробной части и экспоненты. Литералы с плавающей точкой можно представлять либо в десятичной форме, либо в экспоненциальной.

При представлении десятичной формы включают десятичную точку, экспоненту либо и то, и другое; а при представлении экспоненциальной формы — целую часть, дробную часть либо обе части. Знаковая экспонента обозначается символом e или E.

Вот примеры литералов с плавающей точкой:

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

Символьные литералы заключаются в одинарные кавычки; например, ‘x’ может храниться в простой переменной типа char.

Символьный литерал может быть:

  • обычным символом (например, ‘x’);
  • управляющей последовательностью (например, ‘\t’);
  • универсальным символом (например, ‘\u02C0’).

В языке С есть определенные символы, которые имеют особое значение, когда им предшествует обратный слэш, например, новая строка (\n) или табуляция (\t).

Вот список таких кодов управляющей последовательности:

  • \\ — символ \
  • \’ — символ ‘
  • \” — символ “
  • \? — символ ?
  • \a — звуковой сигнал
  • \b — возврат на одну позицию (backspace)
  • \f — смена страницы
  • \n — новая строка
  • \r — возврат каретки
  • \t — горизонтальная табуляция
  • \v — вертикальная табуляция
  • \ooo — восьмеричное число (от одной до трех цифр)
  • \xhh … … — шестнадцатеричное число (из одной или нескольких цифр)

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

Когда приведенный выше код компилируется и выполняется, выдается следующий результат:

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

Строковые литералы (константы) заключаются в двойные кавычки “”. Строка содержит символы, похожие на символьные литералы:

  • обычные символы;
  • управляющие последовательности;
  • универсальные символы.

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

Вот примеры строковых литералов. Все три формы являются идентичными строками:

Определение констант

В языке С есть два простых способа определения констант:

  • Использование препроцессора #define.
  • Использование ключевого слова const.

Препроцессор #define

Ниже приведена форма использования препроцессора #define для определения константы:

Следующий пример детально объясняет эту форму:

Когда приведенный выше код компилируется и выполняется, выдается следующий результат:

Ключевое слово const

Префикс const используется для объявления констант с определенным типом следующим образом:

Пример, указанный ниже, детально объясняет эту форму:

Когда приведенный выше код компилируется и выполняется, выдается следующий результат:

Обратите внимание: хорошей практикой программирования является определение констант в ЗАГЛАВНЫХ БУКВАХ.

Все о литералах в вопросах разработки

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

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

Определение

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

Нужно запомнить следующие особенности literal:

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

Настоящие именованные константы тоже не подлежат в программировании редактированию во время непосредственного исполнения приложения. В некоторых языках разработки (пример – Delphi) при помощи ключевого слова «const» (без кавычек) иногда обозначаются инициализированные до начала обработки кода статические переменные. Такие компоненты могут редактироваться в процессе работы приложения.

Использовать разнообразные типы литералов не слишком трудно. Но сначала нужно знать, как выглядят соответствующие компоненты. Пример выше поможет лучше разобраться в соответствующем вопросе.

Здесь «1» и «Кот» — это литералы, а string pet и int number – непосредственные переменные.

Разновидности

Почти каждый язык программирования позволяет использовать разнообразные типы literals. В зависимости от «разновидности» будет меняться содержание литерала.

В языках разработки предусматриваются примитивные типы. Они отличаются по синтаксису в ЯП. Далее будут приведены примеры того, в коде выглядят литералы Java и C#. Чаще всего встречаются следующие типы литерала:

  • символьный;
  • строковый;
  • логический;
  • пустое значение (null);
  • регулярное выражение;
  • литералы-функции;
  • литералы-объекты.

Далее использование рассматриваемого компонента будет разобрано на примере C# и Java. На второй язык программирования сделан больший упор ввиду его повсеместного и стремительного распространения.

Числа

Первый вариант – это числовые литералы. Они бывают:

  • целочисленные;
  • с плавающей запятой.

Целочисленный литерал – это почти то же самое, что и целые числа. Соответствующая запись является элементарной. Все числовые компоненты записываются в привычной, «стандартной» форме без указывающих символов и прочих составляющих.

Любое число в Java – это по умолчанию целочисленный literal. Допускается явное задание значения переменной или количества итераций в имеющемся цикле. В Java поддерживаются 4 системы счисления:

  • двоичная;
  • десятичная;
  • шестнадцатеричная;
  • восьмеричная.

При рассмотрении числовых литералов в Java нужно запомнить – в JDK 7 появилась возможность записи двоичных значений. Для этого используются префиксы 0b и 0B, а после осуществляется запись с использованием нулей и единиц.

Несмотря на то, что числовые (целые) задаются в разных системах счисления, они будут обрабатываться как десятичные. Это значит, что выход за пределы значений приводят к ошибкам компиляции:

По умолчанию целочисленный literal в Java имеет тип int. Если его «параметр» выйдет за пределы присваиваемой переменной, значит в приложении на этапе компиляции возникнет ошибка. Можно использовать тип long. Для этого в конце строчки необходимо выставить символ «L»:

А вот так выглядит присваивание значения «целому» литералу в C#:

Целочисленные «параметры» могут быть как положительными, так и отрицательными.

С плавающей точкой (вещественные)

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

Вещественный тип необходимо можно представить несколькими способами:

  • классической десятичной дробью;
  • в научном виде (дробь + суффикс в виде e или E и степени 10).

В Java второй вариант сохраняется в переменной и обрабатывается точно так же, как и классическая форма представления.

Числа с плавающей точкой – это значит, что переменная будет иметь тип double по умолчанию. Можно задействовать float. Для этого в конце строки необходимо поставить f или F:

А вот – пример в C#:

Рассматривая типы существующих литералов, нужно запомнить – в Java нельзя создать литерал-объект. К такому элементу имеет отношение только null.

Строковый вариант

Следующий вариант – это строковый literal. По названию становится ясно – он представляет собой какую-то запись. Строковый литерал – это набор символов, заключенных в двойные кавычки в программном коде. Является достаточно распространенным типом. Он применяется на практике так же часто, как и числовой. Строковый literal может включать в себя служебные символы, которые требуется экранировать (escape-последовательности).

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

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

Символьные

Символьные литералы в Java представлены кодовыми таблицами Unicode. Каждый символ – это 16-бит. Символьный literal обозначается при помощи одинарных кавычек.

Существуют два вида символьных записей:

  1. Обычный вариант. Это то, что можно ввести непосредственно с клавиатуры.
  2. Специальный. Символы, которые не получится напечатать на клавиатуре.

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

Символы, которые нельзя задать в консоли «по умолчанию», допускается использовать в 16-битовом коде. Для этого он указывается с префиксом \u. В восьмеричном стиле задействован обратный слеш.

В C# среди использующихся типов литералов отдельно выделяют управляющие последовательности. Если компилятор их встречает, то он воспринимает «команду» как существующую, а не как запись «слеш + буква». Шестнадцатеричный код тоже заключается в одинарные кавычки.

Логические

В ЯП существуют различные типы так называемых литералов, составляющие значимую часть кода. Последний распространенный вариант – это логическая разновидность. Принимает всего 2 значения – «истина» и «ложь». Это – «магический» тип, который позволяет работать с переменными вида boolean.

Используется для обозначения констант true и false в приложении:

Использовать соответствующий компонент в блоках с if можно, но такой вариант является моветоном.

Отдельно стоит отметить «магический» тип – null. Это ссылка, которая не указывает ни на один объект. Представлено пустым значением.

Хотите освоить современную IT-специальность? Огромный выбор курсов по востребованным IT-направлениям есть в Otus!

String literal

Каждый s-char (изначально из несырьевых строковых литералов)или r-char (изначально из сырьевых строковых литералов)(с C++11)инициализирует соответствующий элемент(ы)в объекте строкового литерала.s-char или r-char (начиная с C++11)соответствует более чем одному элементу,если и только если он представлен последовательностью из более чем одной кодовой единицы в соответствующей кодировке символов строкового литерала.

Если символ не имеет представления в соответствующей кодировке,

  • если строковый литерал является обычным строковым литералом или широким строковым литералом,то он условно поддерживается и кодируется последовательность кодовых единиц,определенная реализацией;
  • в противном случае (строковый литерал закодирован в UTF),строковый литерал неверно сформирован.

Каждая числовая управляющая последовательность соответствует одному элементу.Если значение,указанное управляющей последовательностью,вписывается в беззнаковую версию типа элемента,то элемент имеет указанное значение (возможно,после преобразования к типу элемента);в противном случае (указанное значение выходит за пределы диапазона)строковый литерал неправильно сформирован.(начиная с C++23).

Concatenation

Строковые литералы, расположенные рядом, объединяются на этапе перевода 6 (после препроцессора). То есть «Hello,» » world!» дает (единственную) строку «Hello, world!» . Если две строки имеют одинаковый префикс кодировки (или ни один из них не имеет его), результирующая строка будет иметь один и тот же префикс кодировки (или не будет префикса).

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

Если рядом находится строковый литерал UTF-8 и широкий строковый литерал,то программа плохо сформирована.

Любая другая комбинация префиксов кодировок может поддерживаться или не поддерживаться реализацией.Результат такого конкатенирования определяется реализацией.

Любая другая комбинация префиксов кодировки является неправильной.

Notes

Нулевой символ ( ‘\0′ , L’\0’ , char16_t() и т. Д.) Всегда добавляется к строковому литералу: таким образом, строковый литерал «Hello» является const char[6] содержащим символы ‘H’ , ‘e’ , ‘l’ , ‘l’ , ‘o’ и ‘\0’ .

Кодирование обычных строковых литералов (1) и расширенных строковых литералов (2) определяется реализацией. Например, gcc выбирает их с помощью параметров командной строки -fexec-charset и -fwide-exec-charset .

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

Строковые литералы могут использоваться для инициализации массивов символов . Если массив инициализируется как char str[] = «foo»; , str будет содержать копию строки «foo» .

Могут ли строковые литералы перекрываться и дают ли последовательные оценки строкового литерала один и тот же объект,не уточняется.Это означает,что одинаковые строковые литералы могут быть равны или не равны при сравнении по указателю.

Попытка изменить строковый литерал приводит к тому,что undefined behavior : они могут храниться в .rodata только для чтения хранилище (например, .rodata ) или объединяться с другими строковыми литералами:

Строковые литералы можно преобразовать и присвоить неконстантным char* или wchar_t* для совместимости с C, где строковые литералы имеют типы char[N] и wchar_t[N] . Такое неявное преобразование устарело.

Строковые литералы нельзя преобразовать или присвоить неконстантному CharT* . Явное приведение (например const_cast ) должно использоваться, если требуется такое преобразование.

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

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

Хотя конкатенация литералов смешанной ширины строки разрешена в C++11,все известные компиляторы C++отвергают такую конкатенацию,и опыт ее использования неизвестен.В результате,в C++23 разрешение смешанной конкатенации литералов широкой строки удалено.

Example

Defect reports

Следующие отчеты о дефектах,изменяющих поведение,были применены ретроактивно к ранее опубликованным стандартам C++.

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

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

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

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

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

  • 1. Общие сведения
  • 2. Строковой литерал на позиции инициализатора массива char’ов
  • 3. Строковой литерал внутри оператора sizeof
  • 4. Строковой литерал во всех прочих случаях
  • 5. Какие из всего этого следуют выводы
    5.1. Хранение больших массивов строк
    5.2. Когда можно, а когда нельзя модифицировать строку
    5.3. Возврат строки из функции
    5.4. Переиспользование памяти под неявные объекты для строк
    5.5. Применение оператора [] к строковому литералу
  • 6. Склеивание строковых литералов компилятором
  • 7. Ссылки на темы, где обсуждался данный вопрос

1. Общие сведения

Ещё одна конструкция языков Си и Си++, которая часто приводит в затруднение начинающих — это строковой литерал. Начинающим, как правило, трудно понять, чем принципиально отличаются две следующие конструкции:

Термин "строка" имеет очень много смыслов, с технической стороны различающихся в разных контекстах. В контексте языков типа Бэйсик или Паскаль слово "строка" имеет один смысл, в контексте C’шного заголовочного файла string.h — другой смысл, в контексте C++’ного заголовочного файла string — третий смысл, и т.д. Чтобы не путаться с прочими смыслами, я буду пользоваться техническим термином "строковой литерал", который по смыслу означает "строковая константа". Строковым литералом называется заключённая в двойные кавычки строка.

Семантика строкового литерала в языках C/C++ имеет двоякий смыл и зависит от того, в каком месте кода он (строковой литерал) встретился. И эти два различных случая отражены в вышеидущем примере.

2. Строковой литерал на позиции инициализатора массива char’ов

Первая возможность использования строкового литерала — это инициализация массива char’ов. Данная конструкция возникает только в тех случаях, когда описывается переменная, являющаяся массивом char’ов и через знак "=" написана строка, которая инициализирует данный массив. В таком случае строковой литерал следует трактовать как константный массив-инициализатор, состоящих из элементов типа char. Т.е. запись

ВНИМАНИЕ!
В первом комментарии к статье мне любезно сообщили об ошибке. Поведение для Си и для Си++ немного различается. А потому нижеидущий текст (до конца раздела 2) гарантированно справедлив для языка Си, но требует небольшой доработки для языка Си++

При этом есть один очень хитрый момент, касающийся включения в этот инициализатор элемента ‘\0’. И этот момент иногда вводит в заблуждение даже тех, кто имеет хороший опыт программирования. Если массив задан без указания размера (т.е. с пустыми квадратными скобками), то в инициализатор включается хвостовой символ ‘\0’, как это было указано в вышеидущем примере. Т.е., условно говоря, sizeof от инициализатора (и, соответственно, переменной типа массив) будет равен количеству символов в строке плюс единица. Однако если у массива указан размер, то хвостовой ‘\0’ в инициализатор НЕ включается.

Таким образом, если мы напишем

то такая запись будет эквивалентной

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

Хитрость заключается в том, что если мы укажем размер массива равный 3, то хвостового нуля в инициализаторе уже не будет (потому что размер инициализатора совпадает с размером массива). При этом код остаётся абсолютно корректным с точки зрения языка, хотя начинает представлять собой некоторый бардак с точки зрения программиста, который слишком привык к тому, что под строкой подразумевается набор символов с хвостовым нулём.

Если мы напишем такой пример:

то при исполнении на многих компиляторах мы получим код, который при исполнении напечатает нам "abcdefghi". Связано это с тем, что компилятор, как правило, положит три массива "a", "b" и "c" в память подряд друг за другом и таким образом в памяти сформируется набор данных размером 10 байт: ‘a’, ‘b’, ‘c’, ‘d’, ‘e’, ‘f’, ‘g’, ‘h’, ‘i’, ‘\0’. Когда мы подаём в printf указатель на массив "a", то внутри себя функция printf уже не знает ни о каких переменных и будет работать с этим указателем как со строкой: т.е. с набором символов, который заканчивается нулём.

является ошибочной, потому как размер инициализатора больше, чем размер массива.

В случае с инициализацией многомерных массивов char’ов имеем всё ровно то же самое:

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

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