Может кто-нибудь объяснить, что происходит в этом коде на С++. Он компилируется и отлично работает в Linux.
#include <iostream>
using namespace std;
int main = ( cout << "Hello world!\n", 195 );
Может кто-нибудь объяснить, что происходит в этом коде на С++. Он компилируется и отлично работает в Linux.
#include <iostream>
using namespace std;
int main = ( cout << "Hello world!\n", 195 );
Число "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.
Это не действительная программа на С++. На самом деле, он сбой для меня на 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
Это не юридическая программа, но я считаю, что стандарт немного двусмыслен относительно необходимости диагностики или поведения undefined. (С точки зрения качества реализации, я бы ожидал диагностики.)
Он установит глобальную переменную main
(целое число) на значение 195 после печати Hello world. Вам все равно необходимо определить основную функцию для ее выполнения.