web-dev-qa-db-fra.com

Comment lancer une exception en C?

Je l'ai tapé dans google mais n'ai trouvé que des howtos en C++,

comment le faire en C?

82
httpinterpret

Il n'y a pas d'exception en C. En C, les erreurs sont signalées par la valeur renvoyée par la fonction, la valeur de sortie du processus, les signaux transmis au processus ( signaux d'erreur de programme (GNU libc) ) ou par la CPU. interruption matérielle (ou autre erreur de notification de la CPU, le cas échéant) ( Comment le processeur traite-t-il la casse de la division par zéro ).

Les exceptions définies dans C++ et d'autres langages cependant. La gestion des exceptions en C++ est spécifiée dans la norme C++ "Gestion des exceptions S.15", il n'y a pas de section équivalente dans la norme C.

64
Brian R. Bondy

En C, vous pouvez utiliser la combinaison des fonctions setjmp() et longjmp(), définies dans setjmp.h. Exemple de Wikipedia

#include <stdio.h>
#include <setjmp.h>

static jmp_buf buf;

void second(void) {
    printf("second\n");         // prints
    longjmp(buf,1);             // jumps back to where setjmp 
                                //   was called - making setjmp now return 1
}

void first(void) {
    second();
    printf("first\n");          // does not print
}

int main() {   
    if ( ! setjmp(buf) ) {
        first();                // when executed, setjmp returns 0
    } else {                    // when longjmp jumps back, setjmp returns 1
        printf("main");         // prints
    }

    return 0;
}

Remarque: je vous conseillerais en fait de ne pas les utiliser comme ils fonctionnent affreux avec C++ (les destructeurs d’objets locaux ne seraient pas appelés) et il est vraiment difficile de comprendre ce qui se passe. Renvoyer une sorte d'erreur à la place.

29
vava

En clair, le vieux C ne prend pas en charge les exceptions de manière native.

Vous pouvez utiliser d'autres stratégies de traitement des erreurs, telles que:

  • renvoyer un code d'erreur
  • en retournant FALSE et en utilisant un last_error variable ou fonction.

Voir http://en.wikibooks.org/wiki/C_Programming/Error_handling .

18
Lucas Jones

Il n'y a pas de mécanisme d'exception intégré en C; vous devez simuler les exceptions et leur sémantique. Ceci est généralement réalisé en utilisant setjmp et longjmp.

Il y a pas mal de bibliothèques et j'en implémente une autre. Cela s'appelle exceptions4c ; c'est portable et gratuit. Vous pouvez y jeter un coup d'œil et le comparer à autres alternatives pour voir celle qui vous convient le mieux.

17
Guillermo Calvo

C est capable de lancer une exception C++, ce sont quand même des codes machine. Par exemple, dans bar.c

// begin bar.c
#include <stdlib.h>
#include <stdint.h>
extern void *__cxa_allocate_exception(size_t thrown_size);
extern void __cxa_throw (void *thrown_exception, void* *tinfo, void (*dest) (void *) );
extern void * _ZTIl; // typeinfo of long
int bar1()
{
   int64_t * p = (int64_t*)__cxa_allocate_exception(8);
   *p = 1976;
   __cxa_throw(p,&_ZTIl,0);
  return 10;
}
// end bar.c

dans a.cc,

#include <stdint.h>
#include <cstdio>
extern "C" int bar1();
void foo()
{
  try{
    bar1();
  }catch(int64_t x){
    printf("good %ld",x);
  }
}
int main(int argc, char *argv[])
{
  foo();
  return 0;
}

pour le compiler

gcc -o bar.o -c bar.c && g++ a.cc bar.o && ./a.out

sortie

good 1976

http://mentorembedded.github.io/cxx-abi/abi-eh.html contient des informations plus détaillées sur __cxa_throw.

Je ne sais pas s'il est portable ou non, et je le teste avec 'gcc-4.8.2' sous Linux.

9
wcy

Sur Win avec MSVC il y a __try ... __except ... mais c'est vraiment horrible et vous ne voulez pas l'utiliser si vous pouvez éventuellement l'éviter. Mieux vaut dire qu'il n'y a pas d'exceptions.

7
Donal Fellows

Cette question est très ancienne, mais je suis tombée sur elle et je pensais partager une technique: diviser par zéro ou déréférencer un pointeur nul.

La question est simplement "comment lancer", pas comment attraper, ou même comment lancer un type d'exception spécifique. Il y a très longtemps, j’avais une situation où nous devions déclencher une exception de C pour être capturé en C++. Spécifiquement, nous avons eu des rapports occasionnels d'erreurs "d'appels de fonctions virtuelles pures", et nous devions convaincre la fonction _purecall du runtime C de lancer quelque chose. Nous avons donc ajouté notre propre fonction _purecall qui divise par zéro, et boum, nous avons eu une exception que nous pouvions capturer en C++, et nous avons même utilisé une pile amusante pour voir où tout se passait mal.

7
Joe

C n'a pas d'exceptions.

Il existe différentes implémentations de hacky qui tentent de le faire (un exemple à: http://adomas.org/excc/ ).

6
Joe

Comme mentionné dans de nombreuses discussions, la méthode "standard" consiste à utiliser setjmp/longjmp. J'ai posté une autre solution de ce type à https://github.com/psevon/exceptions-and-raii-in-c C'est à ma connaissance la seule solution qui repose sur le nettoyage automatique des ressources allouées. Il implémente des smartpointers uniques et partagés et permet aux fonctions intermédiaires de laisser passer les exceptions sans intercepter les ressources allouées localement et de les nettoyer correctement.

3
user3510229

C ne supporte pas les exceptions. Vous pouvez essayer de compiler votre code C en tant que C++ avec Visual Studio ou G ++ et voir s'il sera compilé tel quel. La plupart des applications C se compileront en C++ sans modifications majeures. Vous pourrez ensuite utiliser la syntaxe try ... catch.

2
Mahmoud Al-Qudsi

Si vous écrivez du code avec un motif de conception Happy Path (c'est-à-dire pour un périphérique intégré), vous pouvez simuler le traitement des erreurs d'exception (ou émulation), avec l'opérateur "goto".

int process(int port)
{
    int rc;
    int fd1;
    int fd2;

    fd1 = open("/dev/...", ...);
    if (fd1 == -1) {
      rc = -1;
      goto out;
    }

    fd2 = open("/dev/...", ...);
    if (fd2 == -1) {
      rc = -1;
      goto out;
    }

    // Do some with fd1 and fd2 for example write(f2, read(fd1))

    rc = 0;

   out:

    //if (rc != 0) {
        (void)close(fd1);
        (void)close(fd2);
    //}

    return rc;
}

En fait, il ne s'agit pas d'un gestionnaire d'exception, mais il vous permet de gérer les erreurs à la sortie d'une fonction.

P.S. Vous devez faire attention à utiliser goto uniquement à partir d'étendues identiques ou plus profondes et à ne jamais sauter de déclaration de variable.

0
Vitold S.