85 votes

Ce code C masqué prétend fonctionner sans main (), mais que fait-il vraiment?

 #include <stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,t,e)

int begin()
{
    printf("Ha HA see how it is?? ");
}
 

Est-ce que cela appelle indirectement main ? Si oui, alors comment?

193voto

haccks Points 33022

C définir l'environnement d'exécution dans deux catégories: autoportant et hébergé. Dans les deux environnement d'exécution d'une fonction est appelée par l'environnement pour le démarrage du programme.
Dans un autoportant programme de l'environnement de démarrage de la fonction peut être définie par l'implémentation tout en hébergé environnement il convient main. Aucun programme en C peut fonctionner sans programme de démarrage de la fonction sur les environnements définis.

Dans votre cas, main est caché par les définitions de préprocesseur. begin() sera étendue à d' decode(a,n,i,m,a,t,e) qui de plus ne sera élargi à d' main.

int begin() -> int decode(a,n,i,m,a,t,e)() -> int m##a##i##n() -> int main() 

decode(s,t,u,m,p,e,d) est paramétrée macro avec 7 paramètres. Liste de remplacement pour cette macro est - m##s##u##t. m, s, u et t 4ème, 1st, 3rd et 2nd paramètre utilisé dans la liste de remplacement.

s, t, u, m, p, e, d
1  2  3  4  5  6  7

Reste ne sont d'aucune utilité (juste à confondre). Argument passé à l' decode est "un,n,i,m,a,t,e" donc, les identificateurs m, s, u et t sont remplacées par des arguments m, a, i et n, respectivement.

 m --> m  
 s --> a 
 u --> i 
 t --> n

71voto

jdarthenay Points 2590

Essayez d’utiliser gcc -E source.c , la sortie se termine par:

 int main()
{
    printf("Ha HA see how it is?? ");
}
 

Ainsi, une fonction main() est réellement générée par le préprocesseur.

37voto

NlightNFotis Points 2689

Le programme en question n' appelez main() en raison expansion de macro, mais votre hypothèse est erronée, - il ne pas avoir à appeler main() à tous!

Strictement parlant, vous pouvez avoir un programme C et être en mesure de le compiler sans avoir un main symbole. main est quelque chose que l' c library s'attend à sauter dans le, après qu'il a terminé son propre initialisation. Habituellement, vous sautez en main de la libc, symbole connu comme _start. Il est toujours possible d'avoir un programme valide, qui exécute simplement de l'assemblée, sans avoir une main. Jetez un oeil à ceci:

/* This must be compiled with the flag -nostdlib because otherwise the
 * linker will complain about multiple definitions of the symbol _start
 * (one here and one in glibc) and a missing reference to symbol main
 * (that the libc expects to be linked against).
 */

void
_start ()
{
    /* calling the write system call, with the arguments in this order:
     * 1. the stdout file descriptor
     * 2. the buffer we want to print (Here it's just a string literal).
     * 3. the amount of bytes we want to write.
     */
    asm ("int $0x80"::"a"(4), "b"(1), "c"("Hello world!\n"), "d"(13));
    asm ("int $0x80"::"a"(1), "b"(0)); /* calling exit syscall, with the argument to be 0 */
}

Compiler le dessus avec des gcc -nostdlib without_main.c, et de voir de l'impression Hello World! sur l'écran tout en émettant des appels système (interruptions) dans un assembly en ligne.

Pour plus d'informations sur cette question en particulier, consultez le ksplice blog

Une autre question intéressante, c'est que vous pouvez également avoir un programme qui compile sans avoir l' main symbole correspond à une fonction C. Par exemple, vous pouvez avoir la suite comme très valable programme C, ne fait que le compilateur gémissement lorsque vous les Avertissements de niveau.

/* These values are extracted from the decimal representation of the instructions
 * of a hello world program written in asm, that gdb provides.
 */
const int main[] = {
    -443987883, 440, 113408, -1922629632,
    4149, 899584, 84869120, 15544,
    266023168, 1818576901, 1461743468, 1684828783,
    -1017312735
};

Les valeurs dans le tableau sont des octets qui correspondent aux instructions nécessaires pour imprimer Hello World " sur l'écran. Pour un compte rendu plus détaillé de la façon dont ce programme fonctionne, jetez un oeil à ce blog, qui est l'endroit où je l'ai aussi lu en premier.

Je veux faire un dernier avis sur ces programmes. Je ne sais pas si ils s'inscrivent comme valide les programmes en C, selon le langage C cahier des charges, mais la compilation de ces et leur exécution est certainement très possible, même s'ils violent la spécification elle-même.

30voto

abhiarora Points 1277

Quelqu'un essaie d'agir comme un Magicien. Il pense qu'il peut nous tromper. Mais nous le savons tous, c l'exécution du programme commence avec main().

L' int begin() sera remplacé par decode(a,n,i,m,a,t,e) par un passage du préprocesseur scène. Puis de nouveau, decode(a,n,i,m,a,t,e) sera remplacé par m##a##i##n. Que par la position de l'association de l'appel de macro, s a une valeur de caractère a. De même, u sera remplacé par " je " et t sera remplacé par 'n'. Et c'est ainsi que, m##s##u##t deviendra main

Concernant, ## symbole dans la macro d'extension, c'est le prétraitement de l'opérateur et il effectue jeton de collage. Lorsqu'une macro est élargi, les deux jetons sur les deux côtés de chaque ‘##' opérateur sont combinés en un seul jeton, qui remplace alors le ‘##' et les deux pions originaux dans la macro d'extension.

Si vous ne me croyez pas, vous pouvez compiler votre code avec -E drapeau. Il va arrêter le processus de compilation après prétraitement et vous pouvez voir le résultat de jeton de collage.

gcc -E FILENAME.c

11voto

Frxstrem Points 5384

decode(a,b,c,d,[...]) mélange les quatre premiers arguments et les joint pour obtenir un nouvel identifiant, dans l'ordre dacb . (Les trois arguments restants sont ignorés.) Par exemple, decode(a,n,i,m,[...]) donne l'identifiant main . Notez que c'est ce que la macro begin est définie.

Par conséquent, la macro begin est simplement définie comme main .

Prograide.com

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.

Powered by:

X