Разминка для мозгов: "Hello, World!"

Случайно в и-нете наткнулся на одну программку, которую и хочу предложить в качестве очередной «разминки для мозгов».

Надо написать программу, которая выводит на консоль строку «Hello, World!». Ограничение: функция main() должна выглядеть так:

int main()
{
    return 0;
}

Глобальный объект, в конструкторе которого на стандартный выходной поток подаётся «Hello world!»?

Ещё так можно:

#include <iostream>

#define return std::cout << "Hello, wordl!" << std::endl; return

int main()
{
    return 0;
}

Конструктор глобального объекта — принимается.

Переопределение return с помощью #define — не спортивно. Формально условия задачи соблюдены, но...

Есть ещё варианты?

Есть ещё одна идейка, можно побаловаться со стеком (программы, который в сегменте стека). Известно, что return извлекает из стека число — адрес возврата и запихивает в стек возвращаемый код (ведь так?). В таком случае можно в конструкторе глобального объекта засунуть в стек адрес глобальной функции f() (с помощью ассемблера, разумеется). Тогда, при выполнении return в main программа не завершится, а передаст управление на f(). А в f() в свою очередь уже выводить сообщение, и завершать программу при помощи std::exit(0). Такое возможно или это бред?

Или посчитать адрес инструкции return, и заменить её на что-нибудь угодное, например на инструкцию безусловного перехода.

porshe, на ассемблере возможно всё (почти) ;-)

Но задача всё-таки подразумевает контекст С/С++ без грязных хаков на ассемблере ))

Конструктор глобального объекта — проехали. Понятно, что там можно выполнить некий код. Каким образом ещё можно это сделать?

Вроде есть команда смены стартовой функции (то есть поменять main на f), но я её не помню, а ничего другое не придумывается :(

Ну, если уж на то пошло, то можно перегрузить оператор сравнения (или какой-нибудь другой) для класса A, создать два объекта A a и A b и создать глобальную переменную bool n = (a == b). Но, это ведь из той же оперы?

Можно так ещё, это ведь не конструктор :)

#include <iostream>

int hello()
{
    std::cout << "Hello world!" << std::endl;
    return 0;
}

int global = hello();

int main()
{
    return 0;
}

Ещё так можно:

#include <iostream>

void *p = (std::cout << "Hello world!" << std::endl);

int main()
{
    return 0;
}

Но, как я понимаю, это решение неверно, так как основано на глобальных переменных?

porshe, почему же? Верно. Инициализация глобальной переменной отличается от конструктора глобального объекта. Например в чистом С с объектом фокус не пройдёт, а с функцией — пожалуйста. Принимается.

Правда твой последний код не скомпилируется. Если только как-то вот так: void *p = reinterpret_cast<void *>(&(std::cout << "Hello world! (5)" << std::endl));.

Перегрузка оператора — из той же оперы: в итоге опять инициализируется глобальная переменная.

А вот selevit совершенно правильно вспомнил про деструкторы глобальных объектов. Они выполняются после функции main. Принимается.

Правда твой последний код не скомпилируется

Нет. Скомпилируется (тестил gcc 4.8.2), так как в iostream перегружен оператор приведения к void*, именно поэтому работают конструкции вида while ( is >> temp ) {}

А есть ещё способы, принципиально отличающиеся от представленных? (да\нет)

Нет. Скомпилируется (тестил gcc 4.8.2),

Не компилируется. Проверял на MSVC++ 2013.
Компилируется. Проверял на TDM-GCC 4.8.1 64-bit.
Вывод: зависит от компилятора.

так как в iostream перегружен оператор приведения к void*, именно поэтому работают конструкции вида while ( is >> temp ) {}

М-м-м... что-то я не нашёл никаких упоминаний о перегрузке приведения к void*. Ссылочку можно?

Конструкции вида while ( is >> temp ) {} работают потому, что в basic_ios (а также в basic_istream и basic_ostream) перегружено приведение к типу bool. while работает с типом bool.

А есть ещё способы, принципиально отличающиеся от представленных? (да\нет)

Почему нет альтернативы «отказываюсь отвечать»? )))

ДА.

Существует мнение, что С++ настолько сложен, что на 100% его не знает никто )) Поэтому мой последний ответ будет «не знаю», а пока что «да».

Ссылочку можно?

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

Забавно ))

Было бы смешно написать большую сложную программу, у которой функция main() была бы пустой ))

А еще-то какие способы есть? Колитесь!

#include <iostream>
#include <cstdlib>

void foo1()
{
   std::cout << "hello " ;
}

void foo2()
{
   std::cout << "world" << std::endl ;
}

int x = (atexit(foo2) , atexit(foo1)) ;

int main( )
{
   return 0 ;
}

Внимание! Это довольно старый топик, посты в него не попадут в новые, и их никто не увидит. Пишите пост, если хотите просто дополнить топик, а чтобы задать новый вопрос — начните новый.

Ответить

Вы можете использовать разметку markdown для оформления комментариев и постов. Используйте функцию предпросмотра для проверки корректности разметки.

Пожалуйста, оформляйте исходный код в соответствии с правилами разметки. Для того, чтобы вставить код в комментарий, скопируйте его в текстовое поле ниже, после чего выделите то, что скопировали и нажмите кнопку «код» в панели инструментов. Иначе ваш код может принять нечитаемый вид.

Либо производите оформление кода вручную, следующим образом:

``` #include <iostream> using namespace std; int main() { // ... } ```

Предпросмотр сообщения

Ваше сообщение пусто.