Смутно с интересным выражением printf()

Прочитав этот код, я наткнулся на следующий оператор printf():

// reset, hide cursor and clear screen
printf("\e[0m\e[?25l\e[2J");

Я должен признать, что я не полностью квалифицированный C-хакер и не совсем понимаю это. Я пошатнулся, удалив аргументы, и я понимаю, что он делает (ну, на самом деле, комментарий на самом деле говорит), но я понятия не имею, как это делается. Кроме того, это что-то вроде трудного для Google.

Как работает этот вызов printf()?

Ответ 1

Это не имеет ничего общего с printf. В стандарте C11 перечислены escape-последовательности в п. 5.2.2, а список состоит из \a, \b, \f, \n, \r, \t и \v. В качестве расширения GCC считает, что \e является escape-последовательностью, которая обозначает символ ASCII Esc (\e может работать также, или ваш компилятор не может поддерживать ни один из них. Обратитесь к документации для вашего компилятора). Ниже приведены не переносимые управляющие последовательности. Они не гарантированно работают одинаково во всех терминалах или даже работают вообще. Лучший способ узнать - это ознакомиться с документацией для вашей системы.

В §6.4.4.4 также описываются восьмеричные escape-последовательности. Например, \033, где 033 является 27 в десятичной форме, а значит, escape-символом в ASCII. Аналогично, вы можете использовать \x1b, который представляет собой шестнадцатеричную escape-последовательность, задающую один и тот же символ.

Если мы проверяем вывод программы с помощью od -c, она показывает 033.

(✿´‿`) ~/test> ./a.out | od -c
0000000 033   [   0   m 033   [   ?   2   5   l 033   [   2   J
0000016

Управляющие последовательности ANSI интерпретируются эмуляторами терминала. C преобразует восьмеричные escape-последовательности восьмеричного кода в символ ASCII Esc. Ваш компилятор, как расширение, может также преобразовать \e или \e. В соответствии с просьбой, краткое объяснение того, что выполняют управляющие последовательности:

  • [0m: сбрасывает все атрибуты SGR
  • [?25l: скрывает курсор
  • [2J: из Википедии:

    Очищает часть экрана. Если n равно 0 (или отсутствует), очистить от курсора до конца экрана. Если n равно 1, очистить от курсора до начала экран. Если n равно 2, очистите весь экран...

Ответ 2

Вызов printf() просто выводит определенную серию байтовых значений. "Магия" заключается в том, что эти значения являются особыми в терминале.

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

http://en.wikipedia.org/wiki/Escape_sequence

Был один особенно популярный терминал под названием "VT100", и большинство терминальных эмуляторов сегодня работают с использованием управляющих последовательностей VT100.

Даже сегодня escape-последовательности полезны. Вы можете написать простую программу на C, которая будет работать на эмуляторах терминалов в Linux, Mac, Windows, мобильных устройствах, в основном везде. Когда вам нужно сделать что-то простое, например, очистить экран, просто вывести правильную escape-последовательность - это самый простой способ.