ВЫДЕРЖКА

Научите свой компьютер быть вежливым

Из Tiny C Projects Дэна Гукина

В этой статье рассказывается о написании программы на C, которая выводит соответствующее приветствие в зависимости от времени суток при запуске компьютера.

Получите скидку 35% на Tiny C Projects, введя fccgookin в поле кода скидки при оформлении заказа на manning.com.

Простое приветствие

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

Написание приветствия

Самая простая программа-приветствие, которую вы можете сделать, — это просто повторение дурацкой программы Hello World, которая появляется на страницах каждой вводной книги по программированию на C со времен Моисея. В листинге 1 показана версия, которую вы можете написать для своей программы приветствия.

Листинг 1 welcome01_basic.c

#include <stdio.h>
  
 int main()
 {
     printf("Hello, Dan!\n");
  
     return(0);
 }

Не строить. Не беги. Если вы это сделаете, используйте эту команду для создания программы с именем greetings:

clang -Wall greet01_basic.c -o greetings

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

Greetings

Убедитесь, что вы добавляете к имени программы префикс пути или полный путь, например:

/home/dang/bin/greetings

или относительный путь:

~/bin/greetings

Сценарий запуска не может волшебным образом найти программные файлы, если вы не укажете путь, например, к моему личному каталогу ~/bin, показанному в примерах. (Я также использую свой сценарий запуска оболочки, чтобы поместить мой личный каталог ~/bin в путь поиска — еще один трюк Linux, найденный где-то в другой книге.)

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

Hello, Dan!

А если тебя зовут не Дэн, то приветствие вызывает больше недоумения, чем веселья.

Добавление имени в качестве аргумента

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

Рассмотрим небольшое улучшение, предлагаемое в листинге 2. Это обновление кода позволяет представить программу с аргументом, что делает ее более гибкой.

Листинг 2 welcome02_basic.c

#include <stdio.h>
  
 int main(int argc, char *argv[])
 {
     if( argc<2)    #A
         puts("Hello, you handsome beast!");
     else
         printf("Hello, %s!\n",argv[1]);    #B
  
     return(0);
 }

#A Количество аргументов для имени программы всегда равно 1. Если это так, выводится сообщение по умолчанию.

#B Все, что было введено после имени программы (только одно слово), представляется как argv[1] и выводится здесь.

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

greetings Danny

Теперь программа выводит следующее сообщение при открытии нового окна терминала:

Hello, Danny!

Это новое сообщение гораздо более радостное, чем исходное, но все еще требует некоторого улучшения.

Время суток

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

Получение текущего времени

Кто-нибудь действительно знает, который час? Компьютер может угадать. Он поддерживает полуточное время, потому что время от времени связывается с сервером времени в Интернете. В противном случае часы компьютера каждый день отставали бы на несколько минут. Поверьте мне, компьютеры делают паршивые часы, но эта истина не мешает вам вытаскивать текущее время из его внутренностей.

Библиотека C изобилует временными функциями, все они определены в заголовочном файле time.h. Тип данных time_t также определяется в заголовке. Для большинства компиляторов тип данных time_t представляет собой положительное целочисленное значение (тип данных long, printf() заполнитель %ld), в котором хранится эпоха Unix. , количество секунд, прошедших с полуночи 1 января 1970 года.

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

Hello, Danny, it's 1624424373

Конечно, значение time_t должно быть преобразовано во что-то более полезное. В листинге 1 показан пример кода. Имейте в виду, что многие функции времени, такие как time() и ctime(), используемые в коде для time01.c, требуют адрес time_t. переменная. Да, это указатели.

Листинг 3 time01.c

#include <stdio.h>
 #include <time.h>    #A
  
 int main()
 {
     time_t now;
  
     time(&now);    #B
     printf("The computer thinks it's %ld\n",now);
     printf("%s",ctime(&now));    #C
  
     return(0);
 }

#A Файл заголовка time.h требуется, чтобы компилятор не рассердился на вас.

#B Для функции time() требуется адрес переменной time_t, перед которым здесь стоит оператор & address-of.

#C Функция ctime() требует аргумента-указателя и возвращает строку с добавлением новой строки.

Вот пример вывода получившейся программы:

The computer thinks it's 1624424373
 Tue Jun 22 21:59:33 2021

Выходные данные показывают количество секунд тик-так с 1970 года. Это же значение используется функцией ctime() для вывода отформатированной строки времени. Этот результат может быть приемлемым для вашей программы приветствия, но данные о времени можно дополнительно настроить. Ключ к раскрытию информации о конкретном времени находится в функции localtime(), как показано в коде в листинге 4.

Листинг 4 time02.c

#include <stdio.h>
 #include <time.h>
  
 int main()
 {
     time_t now;
     struct tm *clock;    #A
  
     time(&now);
     clock = localtime(&now);
     puts("Time details:");
     printf(" Day of the year: %d\n",clock->tm_yday);
     printf(" Day of the week: %d\n",clock->tm_wday);    #B
     printf("            Year: %d\n",clock->tm_year+1900);    #C
     printf("           Month: %d\n",clock->tm_mon+1);    #D
     printf("Day of the month: %d\n",clock->tm_mday);
     printf("            Hour: %d\n",clock->tm_hour);
     printf("          Minute: %d\n",clock->tm_min);
     printf("          Second: %d\n",clock->tm_sec);
  
     return(0);
 }

A# Поскольку localtime() возвращает указатель, лучше всего объявить структуру как указатель.

B# Первый день недели — 0 для воскресенья

C# Чтобы получить текущий год, необходимо добавить 1900 к элементу tm_year . Вы забудете об этом.

D#. tm_mon член находится в диапазоне от 0 до 11.

Я отформатировал код в листинге 4 с кучей пробелов, чтобы вы могли легко идентифицировать элементы структуры tm. Эти переменные представляют лакомые кусочки времени, которые функция localtime() извлекает из значения time_t. Убедитесь, что вы не забыли скорректировать некоторые значения, как показано в листинге 2: Значение года tm_year должно быть увеличено на 1900, чтобы отразить текущий действительный год; значение месяца tm_mon начинается с нуля, а не с единицы.

Вывод тривиален, поэтому мне не нужно его показывать — если только вы не пришлете мне чек на 5 долларов. Тем не менее, смысл кода в том, чтобы показать, как вы можете получить полезную информацию о времени, с помощью которой должным образом приправить приветствие терминала.

Смешивание общего времени суток

Программа, которую я написал несколько лет назад для своего компьютера с DOS, называлась GREET.COM. Это была часть программы AUTOEXEC.BAT моего компьютера, которая запускалась каждый раз, когда я запускал свой старый добрый IBM PC. Поскольку я люблю ностальгические вещи, я сохранил копию программы. Написан на ассемблере x86, работает под DOSBox. Ах, сладкий аромат цифрового прошлого. Пахнет озоном.

Увы, у меня нет исходного кода моей программы GREET.COM. По памяти (и на разборке) я вижу, что код выбирает текущий час дня и выводит соответствующее приветствие времени суток: доброе утро, добрый день или добрый вечер. Вы можете написать тот же трюк, но на C для вашего текущего компьютера, а не на ассемблере x86 для древнего IBM PC.

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

Листинг 5 welcome03_time.c

#include <stdio.h>
 #include <time.h>
  
 int main(int argc, char *argv[])
 {
     time_t now;
     struct tm *clock;
     int hour;
  
     time(&now);
     clock = localtime(&now);
     hour = clock->tm_hour;    #A
  
     printf("Good ");
     if( hour < 12 )    #B
         printf("morning");
     else if( hour < 17 )    #C
         printf("afternoon");
     else    #D
         printf("evening");
  
     if( argc>1 )    #E
         printf(", %s",argv[1]);
  
     putchar('\n');
  
     return(0);
 }

#A Это утверждение предназначено для удобства, чтобы избежать повторного использования clock->tm_hour многократного

#B До полудня скажите "Доброе утро"

#C С полудня до 17:00 говорите "Добрый день"

#D В противном случае уже вечер

#E Проверить и вывести первый аргумент командной строки

Предполагая, что встроенная программа называется greetings, что пользователь вводит Дэнни в качестве аргумента командной строки и что сейчас 4 часа дня, вот выход:

Good afternoon, Danny

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

Для дополнительного юмора вы можете добавить тест на ранние часы, например, с полуночи до 4:00. Выведите какой-нибудь причудливый текст, например «Работаете допоздна?» или «Ты еще не спишь?» О, шутливость! Я надеюсь, что ваши бока не болят.

Добавление информации о времени

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

printf(“Good day, %s\n”,argv[1]);
 printf(“It’s %s”,ctime(&now);

Эти два утверждения должны дать вам представление о том, как может выглядеть код. Тем не менее, программа ленивая. Лучше включить функцию strftime(), которая форматирует строку отметки времени в соответствии с вашими требованиями.

Функция strftime() работает аналогично printf() со специальной строкой, которая форматирует информацию о времени. Вывод функции сохраняется в буфере, который ваш код может использовать позже. Код, показанный в листинге 6, демонстрирует это.

Листинг 6greet04_time.c

#include <stdio.h>
 #include <time.h>
  
 int main(int argc, char *argv[])
 {
     time_t now;
     struct tm *clock;
     char time_string[64];    #A
  
     time(&now);
     clock = localtime(&now);    #B
  
     strftime(time_string,64,"Today is %A, %B %d, %Y%nIt is %r%n",clock);
  
     printf("Greetings");
     if( argc>1 )
         printf(", %s",argv[1]);
     printf("!\n%s",time_string);
  
     return(0);
 }

#Хранилище для строки, заполненной функцией strftime().

#B Чтобы функция strftime() работала, необходимо заполнить структуру localtime() tm .

Вы можете просмотреть man страницу для strftime(), чтобы узнать обо всех забавных заполнителях и их функциях. Как и функция printf(), заполнители имеют префикс %. Любой другой текст в строке форматирования выводится как есть. Вот основные моменты оператора strftime() в листинге 6:

Выходные данные отражают строку времени, сгенерированную и сохраненную в буфере time_string[]. Строка времени появляется после общего приветствия, как описано ранее в этой статье:

Greetings, Danny!
 Today is Wednesday, June 23, 2021
 It is 04:24:47 PM

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

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