Les Erreurs de GCC

De Ensiwiki
Aller à : navigation, rechercher


Sommaire

Parlez vous le GCC ?

Lors qu'on est confrontés à ses premiers rapports d'erreurs GCC, on est vite perdus. 10 lignes de codes peuvent facilement produire 10 pages d'erreurs. Il n'en reste pas moins que ces informations sont un moyen indispensable de débugger : parfois le numéro de ligne suffira, mais parfois pas. Voici tout d'abord quelques conseils :

Chasser les erreurs dans l'ordre

La règle number-one pour le décryptage d'un output GCC est :

Seule la première erreur compte.

"Pourquoi GCC affiche-t-il les autres?" me diriez-vous. Je n'en sais rien, mais ce que je sais, c'est que dans 50% des cas, elles ne veulent rien dire. Et c'est bien normal, vous pensez votre code pour qu'il soit exécuté séquentiellement, si une instruction est invalidé les suivantes perdront probablement leur sens.

En fait, c'est surtout pratique quand le temps de compilation devient un peu long : on corrige la première erreur, on relance une compile, et pendant ce temps on peut essayer de corriger les erreurs suivantes, tout en gardant à l'esprit que ça ne sera peut être pas possible. Il faut donc sauter toutes les erreurs qui découlent de la première, pour trouver la seconde véritable erreur. Ça se fait facilement avec un peu d'entrainement, sinon il suffit de passer à une erreur qui vient d'un fichier source différent.

Un exemple simple

const intt reponse = 42;  // Une bête faute de frappe : intt au lieu de int; Une erreur est levée, mais GCC continue quand même !
return reponse;           // Par contre il va lever une autre erreur ici, puisqu'il n'a pas pu déclarer correctement la variable "reponse"

Warnings

warning: implicit declaration of function `...'

warning: initialization makes integer from pointer without a cast

warning: unknown escape sequence `...'

warning: suggest parentheses around assignment used as truth value

warning: unused variable `...'

warning: unused parameter `...'

warning: passing arg of ... as ... due to prototype

warning: assignment of read-only location

warning: cast discards qualifiers from pointer target type

warning: assignment discards qualifiers ...

warning: initialization discards qualifiers ...

warning: return discards qualifiers ...

Erreurs de Syntaxe

Ces erreurs sont obtenues lors de la génération des fichiers .o

`zoubi' undeclared (first use in this function)

parse error before `...'

parse error at end of input

unterminated string or character constant

character constant too long

error: template parameters not used in partial specialization:

error: invalid use of member (did you forget the ‘&’ ?)

error: ‘ClasseZoubi’ is not an accessible base of ‘ClassePoutchi’

ClassePoutchi hérite de ClasseZoubi, mais pas de façon publique. Donc on n'a pas le droit d'accéder aux membres de la classe mère.

il suffit de remplacer

class ClasseZoubi : ClassePoutchi
{
   ...
}

par

class ClasseZoubi : public ClassePoutchi
{
   ...
}

Si vous avez un héritage multiple, pensez à mettre un public à chaque fois :

class ClasseZoubi : public ClassePoutchi, public ClasseSloubi
{
   ...
}

Si vous voulez que l'héritage reste privé, alors vous n'avez pas le droit d'appeler les membres de la classe mère.

error: there are no arguments to ‘vector’ that depend on a template parameter, so a declaration of ‘vector’ must be available

error: declaration of ‘ma_fonction’ outside of class is not definition

Celle là, c'est une erreur "copier-coller" : dans 99% des cas, c'est que vous avez copié le ";" depuis le .h vers le .cpp. En gros vous avez une fonction définie comme ça

void MaClasse::maFonction()';'
{
   sloubi(1);
   sloubi(2);
}

error: field ‘mon_zoubi’ has incomplete type

Un des attributs à l'intérieur d'une classe n'a pas été déclaré complètement, mais juste prototypé.

class zoubi;

class bloubi {
private:
   zoubi mon_zoubi; // C'est invalide, car on ne connait pas le type complet de zoubi
}

Le type incomplet ne peut être utilisé uniquement pour la déclaration d'un pointeur ou d'une référence:

class zoubi;

class bloubi {
private: 
   zoubi* mon_premier_zoubi; // C'est valide, on n'a pas besoin de connaitre le type complet de zoubi pour en faire un pointeur
   zoubi& mon_second_zoubi;  // ni une référence
}

Attention toutefois, Cette erreur peut être sournoise :

class zoubi;

class bloubi {
private: 
   zoubi* mon_premier_zoubi, mon_second_zoubi; // C'est invalide, car le second zoubi n'est pas un pointeur, 
                                               // hé oui, rappelez vous des pièges liés aux déclarations multiples.
}

error: cannot declare variable ‘t’ to be of abstract type ‘Type’

note: because the following virtual functions are pure within ‘Type’

Si vous obtenez cette erreur, c'est que vous avez déjà fait une bonne partie du travail. Vous avez tenté d'utiliser les virtuelles pures, ce qui est tout à votre honneur. Votre code comprend donc une méthode déclarée avec la syntaxe farfelue suivante.

class ClasseMère
{
    virtual void fontionVirtuelle() = 0;
}

Maintenant, il faut vérifier que toutes les classes qui héritent de ClasseMère implémentent cette méthode.

class ClasseFille : public ClasseMère  // Cette classe n'est pas valide : 
                                       // si elle hérite de ClasseMère, il FAUT qu'elle ait la méthode fonctionVirtuelle()
{
    virtual void uneAutreFonction(); 
}
class ClasseFille : public ClasseMère  // Cette classe n'est pas valide non plus,
                                       // rapellez vous qu'une fonction est identifiée par son nom ET le type de chacun de ses arguments
{
    virtual void fontionVirtuelle(int i); 
}

error: ‘template’ (as a disambiguator) is only allowed within templates

Il faut savoir que le mot-clef template à 2 sens : soit dans une déclaration il déclare du code template, soit il sert de "désembiguateur" à l'intérieur d'un template (C++ recycle les mots-clefs...)

Bref, vous avez probablement fait un copier-coller depuis un template vers du code normal. Il suffit de supprimer les templateen trop (ceux qui sont à l'intérieur du code, et ne sont pas suivis par < ... >).

error: using ‘typename’ outside of template

la même qu'au dessus, mais avec typename.

error: function definition does not declare parameters

Le texte de cette erreur fait un peu peur... En fait il n'en est rien, il manque juste un ':'

void MaClasse:maFonction()
{
    ....
}

Au lieu de

void MaClasse::maFonction()
{
    ....
}

error: passing ‘const MaClasse’ as ‘this/monArgument’ argument of ‘maFonction’ discards qualifiers

Le "qualifier" en question est probablement l'attribut const (je n'en ai jamais vu d'autres). En fait, vous essayez de faire passer un const à une fonction qui veut un mutable. Et ça, c'est mal.

void maFonctionConst( const MonType monArgument ) {...}
void maFonctionPasConst( MonType monArgument ) {...}

main()
{
    const MonType monObjet;
    monObjet->maFonctionConst( monObjet );    // Ça c'est ok
    monObjet->maFonctionPasConst( monObjet ); // Ça c'est pas bien
}

Si l'argument en question est 'this', c'est que vous essayez d'appliquer une méthode non-const à un objet const. Rappelez vous que l'appel d'une méthode via -> ou . n'est que du sucre syntaxique pour cacher un passage de l'argument this.

class MaClasse
{
    void maFonctionConst() const {...} // On garantit que cette fonction ne modifie pas this
                                       // Un peu comme si on avait 'void maFonctionConst( const MaClasse* this );'
    void maFonctionPasConst() {...}    // Par contre cette fonction là fait ce qu'elle veut
}

main()
{
    const MaClasse monObjet;
    monObjet->maFonctionConst();    // Ça c'est ok
    monObjet->maFonctionPasConst(); // Ça c'est pas bien
}

error: cannot dynamic_cast ‘scene’ (of type ‘class MaClasseA’) to type ‘class MaClasseB’

(target is not a pointer) (source type is not polymorphic)


error: object missing in reference to ‘Matrix4<double>::content’

Erreurs lors de l'édition de liens

unable to find '-lma_librairie'

GCC utilise un système pour alléger les lignes de compile : À la place d'écrire l'option -Lchemin_long_et/fastidieux/vers/ma_librairie/libMaLib.a On peut écrire -lMaLib Mais cela ne marche que si le repertoire ou se trouvent les libs sont dans le PATH.

A vous de trouvez où se trouve la lib que vous voulez ajouter, et soit changer le PATH, soit utiliser l'option '-L'

undefined reference to 'zoubi'

Cette erreur, c'est 99% des erreurs de linkage (edition de liens en bon français). Pour faire l'executable que vous pourrez lancer, GCC vérifie que toutes les "trucs" apellées dans les .o sont bien définis (soit dans un autre .o, soit dans une librairie). Cette erreur est levée quand un des ces trucs manque à l'appel.

Malheuresement, il y a plein de situations qui vont lever cette erreur...

Il manque une fonction

Il manque un objet statique

Vous utilisez des templates ????

Si vous n'êtes pas bien au point avec les Templates C++, allez faire un tour sur la page correspondante.

Vous avez probablement oublié d'instancier votre code : il n'est donc pas généré par GCC.

Erreurs à l'execution

Voir les pages Valgrind et Gprof et Gdb

Erreur spécifiques au GCC Mac

-lma_librairie et les frameworks

Sous UNIX standard les librairies sont chargés avec -lma_librairie. Sous Mac il est possible de faire ça (rappel: les librairies sont des fichiers .dylib sous mac), mais il est aussi possible de charger des frameworks Mac par gcc.

Un exemple avec la librairie SDL qui est plus simple à installer avec des frameworks (ou alors en passant par Fink). Sous UNIX classique vous aurez:

Compilation : gcc ... -I/usr/include/SDL .... 
Link : gcc ... -lSDL ...

On aura ici :

Compilation : gcc ... -I/Library/Frameworks/SDL.framework/Headers .... 
Link : gcc ... -framework SDL ...

A cause de ce changement vous risquez d'avoir des problèmes lors de la compilation à la main de librairies linux.

$non_lazy_pointer

Ceci est un bug très spécifique mais qui plante un peu tout. Supposons que vous avez un tas de source et que vous en faite une archive des .o avec ar : libtoto.a.

Par la suite il vous suffit de faire : gcc ... pathverslibtoto/libtoto.a ... au moment du link.

Mais là oh surprise:

Undefined reference: 
    unevar$non_lazy_pointer (toto.o)
    ...

Le bug vient du fait qu'un header (mettons machin.h) utilise le mot clef extern. Tel que :

extern int[] unevar;

Alors là plusieurs solutions s'offrent à vous :

  • Éviter de déclarer la variable en extern (peu probable, on l'appelle pas n'importe où)
  • Ne pas faire d'archive (c'est gênant)
  • Inclure le (ou les) objet(s) déclarant les externs à la compilations (la solution la plus simple)