«Мой человек меня понимает»: История фразы «Hello, World!» и ее аналогов
Строчки «Привет, мир!» знакомы всем программистам в мире. Хотя это просто показывает, что код компилируется, загружается, исполняется и выводит данные наружу. Рассказываем, почему стали так популярны именно эти строки, при чем тут один классический учебник по программированию и мультик про цыпленка.
История одного учебника
Канадский пионер разработки Брайан Керниган написал несколько бестселлеров по программированию еще в то время, когда персональные компьютеры только перестали стоить миллионы долларов за одну штуку. Именно в его книге «Введение в язык программирования B» для компании Bell Labs впервые появилась фраза «Hello, world!» в 1973 году:
1 ’hell’; b ’o, w’; c ’orld’;
По совпадению, это и есть дебют знаменитого «Привет, Мир!». К сожалению, деталей возникновения этой фразы не осталось — никто не знает, почему Керниган выбрал именно ее для своей книги. И в своих интервью он везде признавался, что не помнит, как у него появилась мысль использовать «Привет, Мир!» в качестве примера.
«Все, что я помню — мультик, в котором цыпленок выпрыгивал из яйца со словами: «Привет, Мир!», — рассказывал Керниган в своих интервью про эту фразу.
Сейчас никто уже не помнит про язык B, а само руководство не купить даже в печатном варианте. Но почему тогда мы все пишем эту программу? Все просто — она была и в следующей книге Кернигана, «Язык программирования C», которая была настольной книгой практически у каждого разработчика в 80-х годах.
Сейчас трудно представить, чтобы учебник по программированию так сильно изменил индустрию. Чтобы понять, как это могло произойти во времена учебников Кернигана, совершим небольшое путешествие во времени.
Все ненавидят компьютеры
1890 год. Электромеханический табулятор используют для переписи населения в США. Громадина, больше похожая на ткацкий станок, работает с перфокартами. В СССР такие стали использовать с 1925 года.
1940 год. Двухтонный шкаф с барабанчиками расшифровывал немецкие коды и помог победить во Второй мировой. Слово «компьютер» слишком скучное, поэтому для него выбрали более поэтичное название — Turing Bombe.
1970-е. Перфокарты останутся в жизни программистов еще на 30 лет. Даже в 1950 годах коммерческие компьютеры все еще стоили миллионы — и годились только для выполнения арифметических вычислений. Это были компьютеры Zuse 3 и UNIVAC. И только к концу 70-х перфокарты ушли в прошлое и программисты смогли напечатать что-то в консоли.

До учебников Кернигана люди видели компьютеры как неприкосновенный предмет роскоши, доступ к которому имели только академические верха, оборона или правительство.
Читайте также: Это снова я, резиновая уточка: что такое метод Фейнмана и почему с его помощью так просто изучать программирование
Полезные компьютеры
Первые руководства по программированию через интерфейсы начинались с одного и того же — они горячо убеждали читателя в том, что компьютеры на самом деле полезны. Более того, первые мини-компьютеры даже компьютерами не назывались: маркетологи не хотели, чтобы инновационный продукт связывали с этими «проклятыми» громадинами.
Если верить доктору Джону Маунту, то «Привет, Мир!» распространилось как раз в этот переломный момент.
Кроме этой фразы, программистам предлагались и другие: в книге 1964 года под названием «Мой компьютер любит, когда я говорю с ним на Basic», введение убеждает читателя в общей пользе изучения программирования. А один из примеров кода должен вывести на экран фразу: «МОЙ ЧЕЛОВЕК МЕНЯ ПОНИМАЕТ».
И сейчас на свете есть миллион способов написать первую программу, но «Привет, Мир!» до сих пор самый известный.
Никогда не останавливайтесь: В программировании говорят, что нужно постоянно учиться даже для того, чтобы просто находиться на месте. Развивайтесь с нами — на Хекслете есть сотни курсов по разработке на разных языках и технологиях
Почему hello world
Вы когда-нибудь задумывались почему на первых страницах книг по изучению ЯП в листингах кода используется фраза «Hello, World»? Эта фраза также встречается в ознакомительных курсах или вводных статьях по какому-нибудь ЯП. Возможно современные авторы и разработчики копируют опыт прошлого поколения, но тогда откуда его копировали вторые?
История возвращает нас в 70е годы. В 1973 году Брайан Керниган написал статью, ”A Tutorial Introduction to the Language B” (копия на webarchive), в которой он написал несколько программ на языке B, чтобы показать основные идеи этого языка, где среди прочего включался вывод на экран строки «Hello, World». Затем пример Hello World был приведен во внутреннем меморандуме компании Bell Laboratories в 1974 году, а после в книге The C Programming Language 1978 года. Конечно, есть отсылки, что в действительно первая «Hello, World» программа была написана еще в 1967 на языке BCPL, однако свое распространение подход к ознакомлению с ЯП получил благодаря Брайану Кернигану.

Брайан Керниган. Университет Мэриленд (1982)
Так почему феномен «Hello, World» закрепился в культуре разработке спустя множество десятилетий? В то время был популярный учебник по BASIC, My Computer Likes Me, When I Speak in Basic, начинавшийся с простой программы, которая выводила строчку «MY HUMAN UNDERSTANDS ME» и мы могли бы вполне использовать и ее.
Одно из объяснений успеха «Hello, World», например в статье, The History of ‘Hello, World’, заключается в смене эпох. Например, предыдущее десятилетие характеризовалось использованием массивных мейнфреймов, со всеми вытекающими: большой штат ученых, перфокарты, большие объемы кода. Затем наступает эпоха мини-компьютеров, появляются новые языки, среди которых был и язык С.
Другой важный момент это растущая популярность языка С и его влияние на другие появляющиеся языки. Возможно одним из факторов популярности в то время была разработка операционной системы Unix на C, к которой кстати Брайан Керниган также приложил руку. А почему тот же ранее упомянутый BASIC не вытеснил C или какие-то другие языки и за счет чего язык С остается популярным и по сей день — это уже совсем другая история.
![]()
The C Programming Language Брайан Керниган, 1978 год
Сопроводительные материалы
Hello world с пустой функцией main
Ответ очень прост. Их даже несколько. Самый простой, основанный на свойстве глобальных статических объектов.
int printHelloWorld() < printf("Hello World"); return 0; >static int testVar = printHelloWorld(); int main ()
Это, если С стиль. С++ стиль: создаем класс, в конструкторе добавляем вывод, будет вывод до main, в деструкторе — после.
Отслеживать
ответ дан 19 янв 2011 в 19:10
Nicolas Chabanovsky Nicolas Chabanovsky
51.2k 86 86 золотых знаков 266 266 серебряных знаков 505 505 бронзовых знаков
можно ещё короче int i = puts(«Hello World»); int main(void) < return 0; >
20 янв 2011 в 11:23
создаем класс
Имеется в виду — нужен объект класса 🙂 Т.к. само объявление класса ничего не вызывает.
30 мар 2011 в 23:56
А оптимизация не порежет ли инициализацию к неиспользуемой статичекой переменной? Или это только в шарпе статик инициализируется при первом обращении в коде, до этого он мертв?
11 авг 2012 в 11:21
@Чад хоть и поздно, но отвечу. В шарпе статик инициализируется не при первом обращении — а при загрузке класса. В Си/С++ может быть выкинут лишний модуль, на который нет ссылок — но если модуль присутствует, то все статические переменные будут инициализированы.
22 ноя 2016 в 11:23
Во-первых, не понятно, почему это названо «С стилем». В языке С динамическая инициализация невозможна. Так что сам подход в самой своей сути — именно С++ стиль, что с классами, что без. Во-вторых, без предварительного обявления функции printf программа некорректна. Это относится и к варианту с puts .
1 июл 2017 в 5:55
#define return puts("Hello World"); return int main ()
Не такой красивый вариант как со статикой, но тоже работает.
Отслеживать
ответ дан 20 янв 2011 в 5:25
3,655 2 2 золотых знака 19 19 серебряных знаков 29 29 бронзовых знаков
Вот у меня были подобные мысли, но смутило то, что return занятое слово, разве его дефайном можно?
20 янв 2011 в 7:06
В том-то и дело, что дефайном можно все что угодно. В этом его мощь и. опасность 🙂
20 янв 2011 в 8:36
Старая шутка на ум пришла #define true false
20 янв 2011 в 14:21
И сразу второй строчкой
#define false true
🙂
31 мар 2011 в 10:42
Единственный вариант, работающий в C и C++
28 сен 2011 в 15:36
True programmer напишет это в hex редакторе в машинных кодах. Даже функция main не нужна.
BB 11 01 B9 0D 00 B4 0E 8A 07 43 CD 10 E2 F9 CD 20 48 65 6C 6C 6F 2C 20 57 6F 72 6C 64 21
Немного исправим, воспользовавшись примером выше для соответствию заданию.
using namespace std; #include class hello< public: hello() < ofstream hello; hello.open ("hello.com"); hello put; int main()
Вуаля мы получили программу на языке С++ которая возвращает .com файл, затем запускает его, после чего этот файл через BIOS прерывание выводит на экран Hello, world! При этом наша программа имеет пустую функцию main и не обращается напрямую к стандартном выводу в командную строку. Работает только в DOS command promt .
Отслеживать
1,329 14 14 серебряных знаков 30 30 бронзовых знаков
ответ дан 19 апр 2012 в 12:43
7,786 1 1 золотой знак 28 28 серебряных знаков 49 49 бронзовых знаков
19 апр 2012 в 12:51
Так ведь задание - написать на С++. Кроме того, во многих языках нет main или ему подобных
19 апр 2012 в 13:40
немного исправил для соответствия заданию
19 апр 2012 в 17:55
@igumnov, а теперь сделай в 32битном режиме и PE-заголовком.
19 апр 2012 в 18:05
Изврат не знает пределов.
19 апр 2012 в 18:58
Статические переменные и дефайны не обязательны:
#include int s = printf("Hello world\n"); int main()
Отслеживать
28.5k 12 12 золотых знаков 59 59 серебряных знаков 118 118 бронзовых знаков
ответ дан 31 мар 2011 в 8:51
Alex Kapustin Alex Kapustin
11.7k 1 1 золотой знак 19 19 серебряных знаков 22 22 бронзовых знака
Замена статической переменной на внешнюю означает "статические переменные необязательны"?
19 апр 2012 в 15:12
Хоть переменная i и обладает static storage duration, т.е. с этой точки зрения является "статической", это - первый правильный ответ, благодаря не забытому
1 июл 2017 в 6:36
#include void hello() < puts("Hello, World!"); >#pragma data_seg(".CRT$XIY") void(*pinit)()=&hello; int main() < return 0; >;
Только оказалось, что он только в дебаге работает.
А ещё можно подменить точку входа:
#pragma comment(linker, "/ENTRY:Main") //Вместо прагмы можно использовать параметр командной строки #include //CRT с его printf и puts (не говоря уже о cout) мы, к сожалению, потеряли, поэтому придётся использовать средства ОС int main(void) < return 0; >void Main()
Кстати, у меня эта программка занимает 656 байт после того, как я немного похимичил с ключами компиляции.
Отслеживать
ответ дан 2 дек 2011 в 12:41
5,431 21 21 серебряный знак 32 32 бронзовых знака
що означає макрос pragma?
2 дек 2011 в 15:09
#pragma - это не макрос, а директива препроцессора. pragm'ы бывают разные, их поддержка зависит от компилятора. Конкретно эта записывает указатель на функцию в секцию CRT - стандартной библиотеки C, в недрах которой определена функция mainCRTStartup, которая вызывает main. Перед этим она вызывает все функции из этой секции.
2 дек 2011 в 15:16
@GLmonster, а я попробовал Ваш код в MinGW g++ в Win7. Собирается, но ничего не выводит (точка входа не изменилась). Вы в чем проверяли ?
11 авг 2012 в 19:26
В Visual studio. Прагмы не кросскомпиляторные. Вместо прагмы можно ключ компилятора использовать(которые тоже не кросскомпиляторные).
12 авг 2012 в 6:59
Понятно, что к исходной задаче эти враианты никакого отношения не имеют, как не имеют они никакого отношения к языку С++.
1 июл 2017 в 6:29
#include class hello < public: hello()< std::cout > put; int main()
Отслеживать
51.2k 86 86 золотых знаков 266 266 серебряных знаков 505 505 бронзовых знаков
ответ дан 28 сен 2011 в 15:24
1,823 5 5 золотых знаков 28 28 серебряных знаков 40 40 бронзовых знаков
#include const std::ostream& out = std::cout
Отслеживать
ответ дан 12 янв 2012 в 17:17
929 7 7 серебряных знаков 8 8 бронзовых знаков
Помимо многих предложенных ранее вариантов с выводом текста до выполнения main , предложу вариант с выводом после выполнения main :
#include #include void hw() < puts("Hello world"); >int v = atexit(hw); int main()
Отслеживать
ответ дан 24 фев 2016 в 12:07
28.5k 12 12 золотых знаков 59 59 серебряных знаков 118 118 бронзовых знаков
gcc поддерживает атрибут "constructor", который помещает функцию в init-секцию ELF-файла. Что, в свою очередь, означает, что эта функция вызовется перед функцией main. То есть, то, что нам нужно.
void __attribute__((constructor)) init
Отслеживать
ответ дан 7 сен 2015 в 15:07
1,573 10 10 серебряных знаков 15 15 бронзовых знаков
$ cat hellower.cpp #include "helper.cpp" int main(void)
$ cat helper.cpp #include int hello_helper() < printf("Hello World\n"); return 0; >static int a = hello_helper();
$ g++ hellower.cpp $ ./a.out Hello World
Отслеживать
ответ дан 15 ноя 2015 в 16:43
wonderedman wonderedman
401 4 4 серебряных знака 5 5 бронзовых знаков
И чем это отличается от верхнего ответа?
15 ноя 2015 в 16:50
тем что инклуд всего лишь один перед пустым main() и всё.
8 дек 2015 в 12:08
@VladD: Хотя бы тем, что не забывает включить
1 июл 2017 в 7:21
@AnT: Ну разве что, но это ведь всегда считалось на SO несущественным, точно так же, как и другие называния переменных или там другой стиль скобок. Идейно — ничем.
1 июл 2017 в 7:48
@VladD В обычных задачах - может быть. Но в рамках специфической задачи, явно оговаривающей, в какой части кода разрешается делать исправления, а в какой - нет, расположение каждого добавленного в код символа имеет значение.
1 июл 2017 в 8:06
Первый файл (строго соответствует условию задачи):
$ cat main.cpp int main(void)
$ cat hello.cpp #include int hello_helper() < printf("Hello World\n"); return 0; >static int a = hello_helper();
Makefile для компилятора g++:
$ cat makefile TARGET = hello PREFIX = /usr/local/bin .PHONY: all clean install uninstall all: $(TARGET) clean: rm -f $(TARGET) *.o main.o: main.cpp g++ -c -o main.o main.cpp hello.o: hello.cpp g++ -c -o hello.o hello.cpp $(TARGET): main.o hello.o g++ -o $(TARGET) main.o hello.o install: cp $(TARGET) $(PREFIX)/$(TARGET) uninstall: rm -f $(PREFIX)/$(TARGET)
Отслеживать
ответ дан 30 ноя 2017 в 14:42
221 2 2 серебряных знака 2 2 бронзовых знака
цели main.o и hello.o не нужны в случае использования программы gnu/make
30 ноя 2017 в 14:54
Это инкрементная компиляция. Представим, что наша программа состоит из десятка- другого исходных файлов. Мы вносим изменения в один из них, и хотим ее пересобрать. Использование подхода описанного Вами приведет к тому, что все без исключения исходные файлы будут снова скомпилированы, что негативно скажется на времени перекомпиляции. Решение - разделить компиляцию на два этапа: этап трансляции и этап линковки, что значительно сокращает время отладки и перекомпиляции больших проектов.
30 ноя 2017 в 16:41
то ли вы меня не поняли, то ли я вас не понимаю. в приведённом вами файле makefile не нужны четыре строки с 7 по 10-ю (если интерпретация файла выполняется программой gnu/make). пожалуйста, проверьте и убедитесь сами (программа gnu/make будет выполнять ровно те же действия как при наличии, так и при отсутствии этих четырёх строк).
Пример 'Hello, World!'
Подсказка: в следующих примерах попробуйте выбрать предпочтительную для вас версию Scala.
Ваша первая Scala-программа
Пример “Hello, World!” на Scala выглядит следующим образом. Сначала поместите этот код в файл с именем hello.scala:
- Scala 2
- Scala 3
object hello def main(args: Array[String]) = println("Hello, World!") > >
В этом коде мы определили метод с именем main внутри Scala object -а с именем hello . object в Scala похож на class , но определяет экземпляр singleton, который можно передать. main принимает входной параметр с именем args , который должен иметь тип Array[String] ( args пока можно игнорировать).
@main def hello() = println("Hello, World!")
В этом коде hello - это метод. Он определяется с помощью def и объявляется в качестве основного метода с помощью аннотации @main . Он выводит строку “Hello, World!” на стандартный вывод (STDOUT) с помощью метода println .
Затем скомпилируйте код с помощью scalac :
$ scalac hello.scala
Если вы переходите на Scala с Java: scalac похоже на javac , эта команда создает несколько файлов:
- Scala 2
- Scala 3
$ ls -1 hello$.class hello.class hello.scala
$ ls -1 hello$package$.class hello$package.class hello$package.tasty hello.scala hello.class hello.tasty
Как и Java, файлы .class представляют собой файлы байт-кода, и они готовы к запуску в JVM.
Теперь вы можете запустить метод hello командой scala :
$ scala hello Hello, World!
Если запуск прошел успешно, поздравляем, вы только что скомпилировали и запустили свое первое приложение Scala.
Дополнительную информацию о sbt и других инструментах, упрощающих разработку на Scala, можно найти в главе Инструменты Scala.
Запрос пользовательского ввода
В нашем следующем примере давайте спросим имя пользователя, прежде чем приветствовать его!
Есть несколько способов прочитать ввод из командной строки, но самый простой способ — использовать метод readLine из объекта scala.io.StdIn. Чтобы использовать этот метод, вам нужно сначала его импортировать, например:
- Scala 2 и 3
import scala.io.StdIn.readLine
Чтобы продемонстрировать, как это работает, давайте создадим небольшой пример. Поместите этот исходный код в файл с именем helloInteractive.scala:
- Scala 2
- Scala 3
import scala.io.StdIn.readLine object helloInteractive def main(args: Array[String]) = println("Please enter your name:") val name = readLine() println("Hello, " + name + "!") > >
import scala.io.StdIn.readLine @main def helloInteractive() = println("Please enter your name:") val name = readLine() println("Hello, " + name + "!")
В этом коде мы сохраняем результат из readLine в переменную с именем name , затем используем оператор над строками + для соединения "Hello, " с name и "!" , создавая одно единственное строковое значение.
Вы можете узнать больше об использовании val, прочитав главу Переменные и типы данных.
Затем скомпилируйте код с помощью scalac :
$ scalac helloInteractive.scala
Затем запустите его с помощью scala helloInteractive . На этот раз программа сделает паузу после запроса вашего имени и подождет, пока вы не наберете имя и не нажмете клавишу возврата на клавиатуре. Выглядит это так:
$ scala helloInteractive Please enter your name: ▌
Когда вы вводите свое имя в “приглашении”, окончательное взаимодействие должно выглядеть так:
$ scala helloInteractive Please enter your name: Alvin Alexander Hello, Alvin Alexander!
Примечание об импорте
Как вы ранее видели, иногда определенные методы или другие типы определений, которые мы увидим позже, недоступны, если вы не используете подобное предложение import :
- Scala 2 и 3
import scala.io.StdIn.readLine
Импорт помогает писать и распределять код несколькими способами:
- вы можете поместить код в несколько файлов, чтобы избежать беспорядка и облегчить навигацию в больших проектах.
- вы можете использовать библиотеку кода, возможно, написанную кем-то другим, которая имеет полезную функциональность.
- вы видите, откуда берется определенное определение (особенно если оно не было записано в текущем файле).
