Quelqu'un peut-il s'il vous plaît expliquer ce qui se passe dans ce code C ++. Il compile et s'exécute correctement sur Linux.
#include <iostream>
using namespace std;
int main = ( cout << "Hello world!\n", 195 );
Quelqu'un peut-il s'il vous plaît expliquer ce qui se passe dans ce code C ++. Il compile et s'exécute correctement sur Linux.
#include <iostream>
using namespace std;
int main = ( cout << "Hello world!\n", 195 );
Le nombre "195" est le code d'instruction RET sur x86.
Le compilateur C++ (gcc dans mon cas) est incapable de reconnaître que "principal" n'est pas déclaré comme une fonction. Le compilateur ne voit qu'il y a la "main" d'un symbole, et suppose qu'il fait référence à une fonction.
Le code C++
int main = ( cout << "Hello world!\n", 195 );
initialisation d'une variable dans le fichier-portée. Ce code d'initialisation est exécutée avant que le C/C++ environnement demande de main(), mais après il initialise le "cout" de la variable. L'initialisation de l'affiche "Hello, world!\n", et définit la valeur de la variable "principal" à 195. Après l'initialisation est fait, le C/C++ environnement effectue un appel à la "main". Le programme renvoie immédiatement à partir de cet appel parce que nous avons mis une instruction RET (code 195), à l'adresse de "principal".
Exemple GDB de sortie:
$ 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.
Il n'est pas valide d'un programme C++. En fait, il se bloque pour moi sur Mac OSX après l'impression de "Hello World".
Démontage montre main
est une variable statique, et il y a des initialiseurs:
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)
Pourquoi est-il print "Hello World"?
La raison pour laquelle vous voir "Hello World" imprimé est parce qu'il est exécuté pendant l'initialisation statique d' main
, la statique de la variable de type entier. Les initialiseurs statiques sont appelés avant le C++ runtime tente même de l'appel d' main()
. Quand il le fait, il se bloque, parce qu' main
n'est pas une fonction valide, il est juste un entier 195 dans la section de données de l'exécutable.
D'autres réponses indiquent que c'est valide ret
instruction et il fonctionne très bien sous Linux, mais il bloque sur OSX, car la section est marquée comme non-exécutable par défaut.
Pourquoi pas un compilateur C++ dire que main() n'est pas une fonction et arrêter avec l'éditeur de liens d'erreur?
main()
a C de liaison, de sorte que le linker ne peut pas dire la différence entre le type de symboles. Dans notre cas, _main
réside dans la section de données.
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
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.