Обязательно ли исключать символы табуляции в C и С++?
В C и С++ (и нескольких других языках) горизонтальные табуляторы (ASCII-код 9) в символьных и строковых константах обозначаются в экранированной форме как '\t'
и "\t"
. Тем не менее, я регулярно печатаю символ неэкранированного табулятора в строковых литералах, например, в "A B"
(есть TAB в betreen A
и B
), и, по крайней мере, clang++, похоже, не беспокоит - строка кажется эквивалентны "A\tB"
. Мне больше нравится версия без возврата, так как длинные отступы с несколькими строками лучше читаются в исходном коде.
Теперь я спрашиваю себя, является ли это вообще законным в C и С++ или просто поддерживается моим компилятором. Насколько переносимыми являются невидимые табуляторы в символьных и строковых константах?
Удивительно, но я не смог найти ответ на этот, казалось бы, простой вопрос: ни с Google, ни со стековым потоком (я просто нашел этот неопределенный вопрос).
Ответы
Ответ 1
Да, вы можете включить символ табуляции в строковый или символьный литерал, по крайней мере, согласно С++ 11. Разрешенные символы включают (с моим акцентом):
любой член набора символов источника, кроме двойная кавычка "
, обратная косая черта \
или символ новой строки
(из стандарт С++ 11, приложение A.2)
и набор символов источника включает в себя:
символ пробела, управляющие символы, представляющие горизонтальную вкладку, вертикальную вкладку, фид формы и новую строку, а также следующие 91 графический символ
(из стандарт С++ 11, пункт 2.3.1)
ОБНОВЛЕНИЕ: Я только что заметил, что вы спрашиваете о двух разных языках. Для C99 ответ также да. Формулировка отличается, но в основном говорит то же самое:
В символьной константе или строковом литерале члены набора символов выполнения должны быть представлены соответствующими членами исходного набора символов или [...]
где оба набора символов источника и исполнения включают
управляющие символы, представляющие горизонтальную вкладку, вертикальную вкладку и формы.
Ответ 2
Полностью законно помещать символ табуляции непосредственно в символьную строку или символьный литерал. Стандарты C и С++ требуют, чтобы набор символов источника включал символ табуляции, а строковые и символьные литералы могут содержать любой символ в наборе исходных символов, кроме обратной косой черты, цитаты или апострофа (если это необходимо) и новой строки.
Так что это портативный. Но это не очень хорошая идея, поскольку читатель не может различать разные типы пробелов. Также широко распространены текстовые редакторы, почтовые программы и т.п. Для переформатирования вкладок, поэтому в ходе таких операций могут быть введены ошибки в программу.
Ответ 3
Если вы введете вкладку во вход, то ваша строка будет содержать буквенный символ табуляции, и он останется символом табуляции - он не будет волшебным образом переведен в \t
внутри.
То же самое касается написания кода - вы можете вставлять литеральные символы табуляции в свои строки. Однако учтите следующее:
T T T <--tab stops
012345012345012345012345
foo1 = 'a\tb';
foo2 = 'a b'; // pressed tab in the editor
foo3 = 'a b'; // hit space twice in the editor
Если вы не помещаете курсор в пробелы между a
и b
и не проверяете, сколько там символов, по существу нет способа определить, есть ли там вкладка или фактические пробелы. Но с версией \t
она сразу же отображается как вкладка.
Ответ 4
Когда вы нажимаете клавишу TAB, вы получаете любой код, на который указывает ваша система. Эта кодовая точка может быть или не быть вкладкой в системе, в которой выполняется программа. Когда вы помещаете \t в литерал, компилятор заменяет его соответствующей кодовой точкой для целевой системы. Поэтому, если вы хотите быть уверены, что получаете вкладку в системе, где запускается программа, используйте \t. Это его работа.