Подтвердить что ты не робот

Что здесь происходит в этом коде на С++?

Может кто-нибудь объяснить, что происходит в этом коде на С++. Он компилируется и отлично работает в Linux.

#include <iostream>
using namespace std;
int main = ( cout << "Hello world!\n", 195 );
4b9b3361

Ответ 1

Число "195" - это код команды RET на x86.

Компилятор С++ (gcc в моем случае) не может распознать, что "main" не был объявлен как функция. Компилятор видит только, что есть главный символ, и предполагает, что он ссылается на функцию.

Код С++

int main = ( cout << "Hello world!\n", 195 );

инициализирует переменную в области файлов. Этот код инициализации выполняется до того, как среда C/С++ вызывает main(), но после этого инициализирует переменную "cout". Инициализация печатает "Hello, world!\N" и устанавливает значение переменной "main" на 195. После завершения инициализации среда C/С++ делает вызов "main". Программа немедленно возвращается из этого вызова, потому что мы поместили инструкцию RET (код 195) по адресу "main".

Пример вывода GDB:

$ gdb ./a
(gdb) break _fini
Breakpoint 1 at 0x8048704
(gdb) print main
$1 = 0
(gdb) disass &main
Dump of assembler code for function main:
   0x0804a0b4 <+0>:     add    %al,(%eax)
   0x0804a0b6 <+2>:     add    %al,(%eax)
End of assembler dump.
(gdb) run
Starting program: /home/atom/a 
Hello world!

Breakpoint 1, 0x08048704 in _fini ()
(gdb) print main
$2 = 195
(gdb) disass &main
Dump of assembler code for function main:
   0x0804a0b4 <+0>:     ret    
   0x0804a0b5 <+1>:     add    %al,(%eax)
   0x0804a0b7 <+3>:     add    %al,(%eax)
End of assembler dump.

Ответ 2

Это не действительная программа на С++. На самом деле, он сбой для меня на Mac OSX после печати "Hello World" .

Демонстрация показывает, что main является статической переменной, и для нее есть инициализаторы:

global constructors keyed to main:
0000000100000e20    pushq   %rbp
0000000100000e21    movq    %rsp,%rbp
0000000100000e24    movl    $0x0000ffff,%esi
0000000100000e29    movl    $0x00000001,%edi
0000000100000e2e    leave
0000000100000e2f    jmp __static_initialization_and_destruction_0(int, int)

Почему он печатает "Hello World" ?

Причина, по которой вы видите распечатку "Hello World" , заключается в том, что она запускается во время статической инициализации main, статической целочисленной переменной. Статические инициализаторы вызывают до того, как среда С++ даже пытается вызвать main(). Когда это произойдет, он сработает, поскольку main не является допустимой функцией, в разделе данных исполняемого файла есть только целое число 195.

Другие ответы указывают на то, что это действительная инструкция ret, и она отлично работает в Linux, но она сбой в OSX, потому что по умолчанию этот раздел помечается как неисполняемый.

Почему компилятор С++ не может сказать, что main() не является функцией и останавливается с ошибкой компоновщика?

main() имеет C-связь, поэтому компоновщик не может отличить тип символов. В нашем случае _main находится в разделе данных.

start:
0000000100000eac    pushq   $0x00
0000000100000eae    movq    %rsp,%rbp
...
0000000100000c77    callq   _main ; 1000010b0
0000000100000c7c    movl    %eax,%edi
0000000100000c7e    callq   0x100000e16 ; symbol stub for: _exit
0000000100000c83    hlt
...
; the text section ends at 100000deb

Ответ 3

Это не юридическая программа, но я считаю, что стандарт немного двусмыслен относительно необходимости диагностики или поведения undefined. (С точки зрения качества реализации, я бы ожидал диагностики.)

Ответ 4

Он установит глобальную переменную main (целое число) на значение 195 после печати Hello world. Вам все равно необходимо определить основную функцию для ее выполнения.