2010-11-11 17 views
22

Acabo de ver este hereC Código: ¿Cómo funcionan esto?

#include <stdio.h> 

int main(int argc, char *argv[printf("Hello, world!\n")]) {} 

Lo que esto hace es imprimir "Hello World!"

Pero, ¿qué está pasando aquí?

Lo mejor que puedo imaginar es que se compila y se echa en la parte superior de la pila de ejecución, pero la sintaxis ni siquiera mira legal para mí ...

Respuesta

21

El código hace uso de la característica de matriz de longitud variable C99, que le permite declarar matrices cuyo tamaño se conoce solo en tiempo de ejecución. printf devuelve un número entero igual al número de caracteres que realmente se imprimieron, por lo que el código muestra "¡Hola, mundo!" primero y usa el valor de retorno como el tamaño de argv. La función main en sí no hace nada. La llamada real a printf probablemente entra en el código de inicio generado por el compilador, que a su vez llama al main.

Editar: acabo de comprobar el desmontaje del código generado por gcc y parece que la llamada a printf va dentro main sí, antes de cualquier otro código.

+0

La llamada a 'printf' definitivamente no va en ningún código de inicio pre-' main '. –

+0

@R ..: Eso fue solo una suposición, y lo mejor que puedo hacer. ¿Dónde más podría posiblemente ejecutarse? – casablanca

+0

@R ..: No importa, tienes razón al respecto y respondí mi propia pregunta. :) – casablanca

-1

No soy experto en C, pero parece que los argumentos de la línea de comando se declaran al mismo tiempo que main.

+4

No. Prasoon y casablanca lo tienen. – dmckee

4

char *argv[printf("Hello, world!\n")])

printf() devuelve el número de caracteres impresos.

Así

int main(int argc, char *argv[printf("Hello, world!\n")]) {}

es equivalente a

int main(int argc, char *argv[14]) {}

más una llamada a printf() que imprime "Hello World"

+1

Eso solo es cierto si printf tiene éxito al imprimir todos los caracteres. – Puppy

5

Si puedo averiguar cómo el compilador analiza que, voy a actualizar esto, pero al menos es necesario que haya ninguna conjetura en cuanto a cómo se compila:


objdump --disassemble /tmp/hello (edited): 

080483c4 <main>: 
80483c4:  55      push %ebp 
80483c5:  89 e5     mov %esp,%ebp 
80483c7:  83 e4 f0    and $0xfffffff0,%esp 
80483ca:  83 ec 10    sub $0x10,%esp 
80483cd:  b8 a0 84 04 08   mov $0x80484a0,%eax 
80483d2:  89 04 24    mov %eax,(%esp) 
80483d5:  e8 22 ff ff ff   call 80482fc <[email protected]> 
80483da:  c9      leave 
80483db:  c3      ret  
80483dc:  90      nop 
80483dd:  90      nop 
80483de:  90      nop 
80483df:  90      nop 

Desde ejecutables Linux se basan normalmente en 0x8048000 , la dirección del argumento de printf está en un desplazamiento de 0x00004a0 desde el inicio de la binaria:


xxd /tmp/hello | grep 00004a0 

00004a0: 4865 6c6c 6f2c 2077 6f72 6c64 210a 0000 Hello, world!... 

por lo tanto, la dirección de la cadena es empujada, y printf se llama con que uno arg. Nada mágico en ese nivel, así que todo lo divertido lo hizo gcc.

Cuestiones relacionadas