Трюки от Крыса Крис Касперски Хакер, номер #103, стр. 103-120-1 Сегодняшний выпуск трюков посвящен двум любопытным, но малоизвестным возможностям языка Си — «триграфам» (trigraph) и «диграфам» (digraph), в основном встречающимся в соревнованиях по непонятному программированию, однако в некоторых (достаточно редких) случаях разваливающим программу, написанную без учета их существования. Совет 1: триграфы: жизнь без скобок Ди- и триграфы широко используются в натуральных языках для обозначения «чужеродных» символов, отсутствующих в «своем» алфавите. Последовательность из двух (реже трех) «своих» символов кодирует один «чужой». Просто, как и все гениальное! Например, хангыль (корейское фонематическое письмо) состоит из блоков типа чамо, кодирующих отдельные слоги или даже целые слова. Всего существует 51 чамо, 24 из которых эквивалентны буквам обычного алфавита, а оставшиеся 27 представляют собой комбинации из двух или трех букв (то есть диграфы и триграфы соответственно). Язык Си использует 9 символов, не входящих в наборы ISO 646 и EBCDIC, до сих пор используемые в некоторых терминалах. В результате квадратные и фигурные скобки невозможно ни набрать с клавиатуры, ни отобразить на экране такого терминала, а потому, начиная с самых первых редакций Стандарта, в язык ввели поддержку триграфов, скрестив символы базового набора ISO 646 с двумя знаками вопроса (смотри таблицу 1). Программа, написанная с использованием триграфов, может выглядеть, например, так: Исходный текст программы, написанной с использованием триграфов ??=include <stdio.h> /* # */ int main(void) ??< /* { */ char n??(5??); /* [ и ] */ n??(4??) = '0' - (??-0 ??' 1 ??! 2); /* ~, ^ и | */ printf("%c??/n", n??(4??)); /* ??/ = \ */ printf("??=??=??="); /* ### */ ??> Попробуй подсунуть эту абракадабру коллегам и спроси, что она делает. Кстати, обрати внимание на предпоследнюю строчку, здесь тригафы используются внутри строковых констант и, вместо ожидаемых «??=??=??=», функция printf напечатает три символа решетки! А ведь, не зная о существовании триграфов, о такую комбинацию можно спотыкнуться чисто случайно, долго ломая голову, почему программа работает не так, как это задумывалось. Триграфы поддерживают практически все современные компиляторы, однако если Microsoft Visual C++ задействует триграфы по умолчанию, то Borland C++ для увеличения скорости трансляции использует внешний препроцессор, реализованный в файле trigraph.exe, входящий в штатный комплект поставки компилятора и вызываемый программистом самостоятельно. GCC поддерживает триграфы, но по умолчанию не обрабатывает их внутри строковых констант и делает это только при явном указании ключа ‘-trigraphs’. Подробнее о триграфах можно почитать в Стандарте на Си, в любом хорошем учебнике или Википедии — http://en.wikipedia.org/wiki/C_trigraph. Совет 2: диграфы: элегантный мир Недостаточная выразительность и отвратительная читабельность триграфов привели к тому, что в последней редакции Стандарта ANSI C99 появилась достойная альтернатива в виде диграфов. Они используют всего два символа вместо трех, комбинируя угловые скобки со знаком процента или двоеточия, интерпретируемых как квадратные и фигурные скобки соответственно. Согласитесь, что так нагляднее (причем намного) и гораздо естественнее! |