extern avec l’appel de fonction à l’intérieur du main

En lisant Unix System Design de Maurice Bach, je suis tombé sur un extrait de code.

#include  char *cp; int callno; main() { char *sbrk(); extern catcher(); signal(SIGSEGV, catcher); cp = sbrk(O); printf("original brk value %u\n", cp); for (;;) *cp++ = 1; } catcher(signo) { int signo; callno++; printf("caught sig %d %dth call at addr %u\n", signo, callno, cp); sbrk(256); signal(SIGSEGV, catcher); } 

J’ai été confondu avec deux déclarations dans la méthode principale

char * sbrk ();

capteur externe ();

Je comprends comment fonctionne extern et je sais aussi ce que fait sbrk() mais je ne pouvais pas comprendre pourquoi ont-ils écrit extern avant catcher() et pourquoi char* écrit avant l’appel sbrk() ?

J’ai eu une erreur de compilation sur gcc-4.8.4 sur Ubuntu lors de la compilation de ce code mais le code comstack sans aucune erreur dans Mac. Pourquoi cela arrive-t-il?

 char *sbrk(); extern catcher(); 

Ce sont des déclarations de fonction, pas des appels de fonction. Le code que vous lisez est un ancien style (pré-ANSI) et dans les normes C ultérieures (c99 ou plus récentes), elles ne sont plus valides.

Vous devez append un type de retour explicite à la déclaration de catcher() . La déclaration implicite actuelle signifie qu’elle a un type de retour int . Cependant, la signature correcte pour un gestionnaire de signaux ne spécifie aucune valeur de retour. Lorsque nous ajoutons un type de retour explicite, le mot clé extern n’est plus nécessaire et peut être supprimé.

sbrk est en fait déclaré dans un en-tête normal. Supprimez donc la déclaration et #include . Cependant, sbrk est BSD (et fait partie de SUSv2) et non une fonction C standard, vous devez donc activer la déclaration avec #define _BSD_SOURCE ou #define _XOPEN_SOURCE=500 avant d’inclure unistd.h .

Printf est déclaré dans stdio.h , alors incluons-le. %u est utilisé pour imprimer unsigned int . Les pointeurs doivent être imprimés avec le spécificateur de format %p .

Donc, après une certaine modernisation du code:

 #define _BSD_SOURCE #include  #include  #include  void catcher(); char *cp; int callno; int main(void) { signal(SIGSEGV, catcher); cp = sbrk(O); // You sure this should be an O and not a 0? printf("original brk value %u\n", cp); for (;;) *cp++ = 1; } void catcher(int signo) { callno++; printf("caught sig %d %dth call at addr %p\n", signo, callno, cp); sbrk(256); signal(SIGSEGV, catcher); } 

Veuillez noter que vous devez éviter d’appeler printf depuis un gestionnaire de signal. Voir par exemple Comment éviter d’utiliser printf dans un gestionnaire de signal ou les gestionnaires de signaux et la sécurité des signaux asynchrones

En plus de la réponse de @Klas Lindbäck, il existe d’autres problèmes avec ce code sous les normes C et POSIX actuelles:

 #include < signal.h> char *cp; int callno; main() { char *sbrk(); extern catcher(); signal(SIGSEGV, catcher); cp = sbrk(O); printf("original brk value %u\n", cp); for (;;) *cp++ = 1; } catcher(signo) { int signo; callno++; printf("caught sig %d %dth call at addr %u\n", signo, callno, cp); sbrk(256); signal(SIGSEGV, catcher); } 

Ne pas utiliser sbrk()

sbrk() a été supprimé du standard POSIX. Il n’est plus sûr d’utiliser directement. A partir de la page de manuel Linux :

Évitez d’utiliser brk() et sbrk() : le package d’allocation de mémoire malloc(3) est le moyen portable et confortable d’allouer de la mémoire.

Pourquoi? Parce que de nombreuses fonctions de la bibliothèque C utilisent souvent malloc() / calloc() / realloc() / … en interne, mélanger les appels malloc() et brk() / sbrk() dans le même processus est dangereux . malloc() implémentations de malloc() utilisent souvent brk() / sbrk() interne, donc utiliser sbrk() dans votre propre code pourrait très bien corrompre votre tas.

Ne pas utiliser le signal()

signal() a des problèmes importants . Ce n’est pas du tout cohérent. Utilisez sigaction() place.