Est-il possible d'écrire un programme sans utiliser la fonction main ()?

je continue de recevoir cette question posée dans les interviews:

Ecrire un programme sans utiliser main() fonction?

un de mes amis m'a montré du code en utilisant des Macros, mais je n'ai pas pu le comprendre.

Donc la question est:

Est-il vraiment possible d'écrire et de compiler un programme sans main()?

29
demandé sur Alok Save 2011-08-13 18:11:47

20 réponses

dans la norme C++ a main la fonction est requise, de sorte que la question n'a pas de sens pour la norme C++.

en dehors du C++ standard vous pouvez par exemple écrire un programme spécifique à Windows et utiliser L'une des fonctions de démarrage personnalisées de Microsoft (wMain, winMain, wWinmain). Dans Windows, vous pouvez aussi écrire le programme comme DLL et utiliser rundll32 pour l'exécuter.

en dehors de cela, vous pouvez faire votre propre petite bibliothèque d'exécution. À un moment c'était fréquent sport.

enfin, vous pouvez obtenir intelligent et de répondre que selon la règle ODR de la norme main n'est pas "utilisé", de sorte que tout programme est admissible. Bah! Bien qu'à moins que les intervieweurs aient un bon sens de l'humour inhabituel (et ils n'auraient pas posé la question s'ils l'avaient fait), ils ne penseront pas que c'est une bonne réponse.

17
répondu Cheers and hth. - Alf 2016-06-14 19:58:01

Non, vous ne pouvez pas, sauf si vous écrivez un programme dans un freestanding environment (environnement intégré noyau de système d'exploitation, etc.) où le point de départ ne doit pas nécessairement être main(). Conformément à la norme C++main() est le point de départ de tout programme dans un hosted environment.

par:

C++03 standard 3.6.1 fonction Principale

1 Un programme doit contenir une fonction globale appelée principal, qui est le départ du programme. Il est mise en œuvre-défini si un programme dans un environnement autonome est nécessaire pour définir une fonction principale. [ Note: dans un environnement autoportant, démarrage et la terminaison est définie par la mise en œuvre; le démarrage contient l'exécution des constructeurs pour les objets de namespace scope avec une durée de stockage statique; la terminaison contient l'exécution des destructeurs pour les objets avec une durée de stockage statique.


qu'est-Ce que freestanding Environment & ce qui est x80 xorl %ebx, %ebx movl $exit, %eax int x80 .data str: .ascii "Hello, world!\n" len = . -str .globl _start $ as -o hwa.o hwa.S $ ld hwa.o $ ./a.out Hello, world!

le noyau qui exécute réellement un exécutable ne connaît rien aux symboles internes, il se transfère simplement à un point d'entrée spécifié en binaire dans l'en-tête d'image exécutable.

la raison pour laquelle vous avez besoin d'un main est que normalement votre "programme principal" n'est qu'un autre module. Le point d'entrée est dans le code de démarrage fourni par la bibliothèque et écrit dans une combinaison de C et assembly et ce code de bibliothèque arrive juste à appeler main donc, vous devez normalement fournir un. Mais pour exécuter l'éditeur de liens directement et vous n'avez pas.

Pour inclure un module C1...

Mac:~/so$ cat > nomain.S
.text
.globl start
start:
        call   _notmain
Mac:~/so$ as -o nomain.o nomain.S
Mac:~/so$ cat > notmain.c
#include <unistd.h>

void notmain(void) {
  write(1, "hi\n", 3);
  _exit(0);
}
Mac:~/so$ cc -c notmain.c
Mac:~/so$ ld -w nomain.o notmain.o -lc
Mac:~/so$ ./a.out
hi


1. Et je passe aussi au x86-64 ici.
5
répondu DigitalRoss 2016-06-14 19:42:51

"Sans l'aide de main" peut aussi signifier qu'aucune logique est autorisé à l'intérieur de main, mais main lui-même existe. J'imagine que la question a cette vidé, mais puisqu'il n'est pas effacé ici, c'est une autre réponse possible:

struct MainSub
{
   MainSub()
   {
      // do some stuff
   }
};

MainSub mainSub;

int main(int argc, char *argv[]) { return 0; }

Ce qui va se passer ici, c'est que les trucs en MainSub'constructeur exécuter avant la inutilisables main est exécutée, et vous pouvez placer la logique du programme. Cela nécessite bien sûr C++, et non C (ce qui n'est pas clair non plus d'après les question.)

3
répondu eran 2011-08-13 15:20:34

je pense que la macro référence était de renommer la fonction principale, ce qui suit n'est pas mon code, et démontre ceci. Le compilateur voit toujours une fonction principale, mais techniquement il n'y a pas de main du point de vue de la source. Je l'ai eu ici http://www.exforsys.com/forum/c-and-c/96849-without-main-function-how-post412181.html#post412181

#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(" hello ");
}
2
répondu eon 2011-08-13 14:20:39

aussi longtemps que vous utilisez g++ vous pouvez changer votre point d'entrée avec l'option linker -e, ainsi le code suivant et la commande de compilation peuvent vous permettre de créer un programme sans un main() fonction:

#import <iostream>

class NoMain
{
public:
    NoMain()
    {
        std::cout << "Hello World!" << std::endl;
        exit(0);
    }
} mainClass;

j'ai donné le nom du fichier comme noname.cpp, et l'option Compiler est:

g++ nomain.cpp -Wl,-e,_mainClass -v

Pour dire la vérité, je n'ai pas bien compris pourquoi le code fonctionne très bien. Je soupçonne que l'adresse de la variable globale mainClass est identique au constructeur de l' NoMain classe. Cependant, Je aussi ont plusieurs raisons que je pourrais dire mon hypothèse peut ne pas corriger.

2
répondu Joohae Kim 2016-07-26 19:09:26

sans tenir compte des normes linguistiques spécifiques, la plupart des chargeurs de liens fournissent des moyens de déclarer un nom de fonction (point d'entrée) qui doit être exécuté lorsque le binaire est chargé est chargé en mémoire.

pour le langage C de la vieille école, la valeur par défaut était quelque chose comme 'start' ou '_start', défini dans le crt (C runtime?), qui effectue plusieurs tâches ménagères nécessaires aux fonctions standard c, telles que la préparation du tas de mémoire, l'initialisation des zones variables statiques, l'analyse de la ligne de commande en argc / argv, etc.

peut-être que vous pourriez outrepasser la fonction de point d'entrée si vous prenez assez de soin de ne pas utiliser les fonctions standard qui nécessite ces choses domestiques (par exemple malloc(), free(), printf(), n'importe quelles définitions de classe ont le constructeur personnalisé, ...) Tout à fait restrictif mais pas impossible si vous utilisez des fonctions fournies par o/s, pas par l'exécution C standard.

par exemple, vous pouvez faire un simple helloworld en utilisant la fonction write() sur le descripteur 1.

1
répondu shr 2011-08-13 15:17:25

quand le code C ou C++ tourne, il exécute à une adresse de départ connue, le code initialise ici l'environnement d'exécution, initialise le pointeur de pile, effectue l'initialisation des données, appelle les constructeurs statiques, saute à main ().

le code qui fait cela est lié à votre code au moment de la construction par le linker. Dans le GCC, il est généralement en crt0.s, avec un compilateur commercial, il est peu probable que ce code sera disponible pour vous.

à la fin, il a commencer quelque part et main() est juste un nom symbolique pour cet emplacement. Il est spécifié par la norme de langage de sorte que les développeurs savent comment l'appeler, sinon le code ne serait pas portable d'une chaîne d'outils à l'autre.

si vous écrivez du code pour un système 'Nare-metal' sans OS ou du moins sans OS dans le sens d'un chargeur de processus (les systèmes embarqués incluent souvent un noyau RTOS qui est démarré après main ()), alors vous pouvez en théorie appeler l'entrée de code C pointez tout ce que vous voulez puisque vous avez habituellement le contrôle complet sur le code de démarrage d'exécution. Mais ne serait stupide et un peu pervers.

certains environnements RTOS tels que VxWorks, et la plupart des cadres d'application en général incluent main() )ou son équivalent) dans leur propre code de bibliothèque de sorte qu'il s'exécute avant le code d'application de l'utilisateur. Par exemple, les applications VxWorks commencent à partir de usrAppInit (), et les applications Win32 commencent à partir de WinMain().

1
répondu Clifford 2011-08-19 19:27:47

je réalise que c'est une vieille question, mais je viens de trouver ceci et a dû partager. Il ne fonctionnera probablement pas avec tous les linkers, mais il est au moins possible de tromper ld (je suis sous la version 2.24.51.20140918) en pensant qu'il ya une main- function en faisant ceci:

int main[] {};

ou encore

int main;

vous pouvez alors appliquer l'un des trucs mentionnés ci-dessus pour permettre au programme d'exécuter du code, par exemple en utilisant un constructeur:

struct Main
{
    Main()
    {
        cout << "Hello World!\n";
        exit(0);
    }
} main_;

exit(0) est d'empêcher le tableau d'être "appelé". Bien du plaisir :-)

1
répondu JorenHeit 2014-10-29 12:49:18

peut-être est-il possible de compiler un .section des données et le remplir avec du code?

0
répondu Bytemain 2011-08-13 14:15:40

Ça dépend de ce qu'ils signifient.

ont-ils dire:

Écrire un programme sans fonction main ().

alors généralement non.

Mais il y a des moyens de tricher.

  • Vous pouvez utiliser le pré-processeur pour masquer main() à la vue de tous.
  • la Plupart compilateur vous permettent de spécifier le point d'entrée dans votre code.

    Par défaut, il est main(int,char*[])

Ou n' ils signifient:

Écrire un programme qui exécute le code sans utiliser main (pour exécuter votre code).

c'est une astuce relativement simple. Tous les objets de l'espace de noms global exécutent leurs constructeurs avant que main () ne soit entré et que destruction après main () ne sorte. Donc tout ce que vous devez faire est de définir une classe avec un constructeur qui exécute le code que vous voulez, puis créer un objet dans l'espace de noms global.

Note: le compilateur est autorisé à optimiser ces objets pour le report de la charge (mais généralement pas) mais pour être sûr il suffit de mettre la mondiale dans le même fichier que la fonction principale (qui peut être vide).

0
répondu Martin York 2011-08-13 16:19:33

la fonction main est seulement l'étiquette par défaut pour l'adresse où le programme commencera l'exécution. Donc techniquement Oui c'est possible, mais vous devez définir le nom de la fonction qui commencera l'exécution dans votre environnement.

0
répondu Dawid Królak 2011-08-13 22:26:43

Ecrire une classe et imprimer votre nom dans le constructeur de cette classe et déclarer un objet GLOBAL de cette classe. Si le constructeur de la classe est exécuté avant les principaux. Vous pouvez donc laisser le fichier principal vide et tout de même imprimer votre nom.

class MyClass
{
   myClass()
   {
       cout << "printing my name..." <<endl;
   }
};

MyClass gObj; // this will trigger the constructor.

int main()
{
   // nothing here...
}
0
répondu John Gummadi 2012-12-19 17:53:56

1) Utiliser une macro qui définit main

#include<stdio.h>
#define fun main
int fun(void)
{
printf("stackoverfow");
return 0;
}

Sortie:

stackoverflow

#include<stdio.h>
#define fun m##a##i##n
int fun()
{
printf("stackoverflow");
return 0;
}
0
répondu anshuman singh 2014-09-09 15:26:52

oui, il est possible d'écrire un programme sans main().

Mais il utilise main() indirectement.

programme suivant vous aidera à comprendre..

#include<stdio.h>
#define decode(s,t,u,m,p,e,d) m##s##u##t
#define begin decode(a,n,i,m,a,r,e)
int begin()
{
printf(” you are inside main() which is hidden“);
}

l'opérateur '# # ' s'appelle l'opérateur de collage ou de fusion de jeton. Qui est nous est possible de fusionner deux ou plusieurs caractères.

Dans la 2ème ligne du programme-

définir les décoder(s,t,u,m,p,e,d) m##s##u##t

Que fait le préprocesseur ici? Le la macro-décodage (s,t,u,m,p,e,D) est élargi comme "msut" (l'opérateur ## fusionne m,s, u & t dans msut). La logique est quand vous passez(s,t,u,m,p,e,d) comme argument il fusionne le 4ème,1er,3ème et le 2ème caractères (tokens)

Maintenant, regardez le troisième ligne du programme –

définir commencer à décoder(a,n,i,m,a,r,e)

ici le préprocesseur remplace la macro "begin" par le décodage d'expansion(a,n,i,m,a,r,e). Selon la définition macro de la ligne précédente, argument doit être élargi de sorte que les 4ème,1er,3ème et le 2ème caractères doivent être fusionnés. Dans l'argument(a,n,i,m,a,r,e) 4ème,1ère,3ème et la 2ème personnages sont ‘m’,’a’,’i’ et ‘n’.

donc il remplacera commencer par main() par le préprocesseur avant que le programme est transmis pour le compilateur. C'est ça...

0
répondu Saraswati Katakdhond 2018-01-16 05:59:05

selon les normes, main () est requis et le point de départ des environnements hébergés. C'est pourquoi vous devez utiliser des trucs pour cacher l'apparence évidente principale, COMME LE truc posté ci-dessus.

#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(" hello ");
}

ici, main est écrit par les Macro trucs. Il n'est peut-être pas clair à la fois, mais il mène finalement à main. Si c'est la réponse valable à votre question, cela pourrait être fait très facilement, comme ceci.

# include <stdio.h>
# define m main

int m()
{
    printf("Hell0");
}
-4
répondu Bharat Kul Ratan 2011-08-13 21:59:07