web-dev-qa-db-fra.com

Comment empêcher plusieurs définitions en C?

Je suis un débutant en C et j'essayais juste d'écrire une application console avec Code :: Blocks. Voici le code (simplifié): main.c:

#include <stdio.h>
#include <stdlib.h>
#include "test.c" // include not necessary for error in Code::Blocks

int main()
{
    //t = test(); // calling of method also not necessary
    return 0;
}

test.c:

void test() {}

Lorsque j'essaie de créer ce programme, il donne les erreurs suivantes:

 * chemin *\test.c | 1 | définition multiple de `_ test '| 
 obj\Debug\main.o: * chemin *\test.c | 1 | d'abord défini ici | 

Il n'y a aucun moyen de multiplier le test de définition (bien que je ne sache pas d'où vient le trait de soulignement) et il semble très improbable que la définition soit en quelque sorte incluse deux fois. C'est tout le code qui existe.

J'ai exclu que cette erreur soit due à un conflit de nommage avec d'autres fonctions ou fichiers appelés test ou test.c. Notez que le multiple et la première définition sont sur la même ligne dans le même fichier.

Est-ce que quelqu'un sait ce qui cause cela et ce que je peux faire? Merci!

38
Jordi

Vous compilez en fait le code source de test.c Deux fois:

  • La première fois que vous compilez test.c Lui-même,
  • La deuxième fois lors de la compilation de main.c Qui inclut toutes les sources de test.c.

Ce dont vous avez besoin dans votre main.c Pour utiliser la fonction test() est une simple déclaration, pas sa définition. Ceci est réalisé en incluant un fichier d'en-tête test.h Qui contient quelque chose comme:

void test(void);

Cela informe le compilateur qu'une telle fonction avec des paramètres d'entrée et un type de retour existe. Ce que fait cette fonction (tout ce qui se trouve dans { Et }) Est laissé dans votre fichier test.c.

Dans main.c, remplacez #include "test.c" Par #include "test.h".

Un dernier point: vos programmes étant plus complexes, vous serez confronté à des situations où les fichiers d'en-tête peuvent être inclus plusieurs fois. Pour éviter cela, les sources d'en-tête sont parfois entourées de définitions de macro spécifiques, comme:

#ifndef TEST_H_INCLUDED
#define TEST_H_INCLUDED

void test(void);

#endif
84
mouviciel

Le trait de soulignement est mis là par le compilateur et utilisé par l'éditeur de liens. Le chemin de base est:

main.c
test.h ---> [compiler] ---> main.o --+
                                     |
test.c ---> [compiler] ---> test.o --+--> [linker] ---> main.exe

Ainsi, votre programme principal devrait inclure le fichier d'en-tête du module de test qui ne devrait être composé que de déclarations, comme le prototype de fonction:

void test(void);

Cela permet au compilateur de savoir qu'il existe lorsque main.c est en cours de compilation mais que le code réel est dans test.c, puis test.o.

C'est la phase de liaison qui relie les deux modules.

En incluant test.c dans main.c, vous définissez la fonction test () dans main.o. Vraisemblablement, vous liez ensuite main.o et test.o, qui contiennent tous deux la fonction test ().

26
paxdiablo

Vous ne devez pas inclure d'autres fichiers source (* .c) dans les fichiers .c. Je pense que vous voulez avoir un fichier header (. H) avec la DÉCLARATION de la fonction de test, et avoir sa DÉFINITION dans un fichier .c distinct.

L'erreur est causée par plusieurs définitions de la fonction de test (une dans test.c et une autre dans main.c)

10
Kasprzol

J'ai eu un problème similaire et je l'ai résolu de la manière suivante.

Résolvez comme suit:

Les déclarations de prototype de fonction et la variable globale doivent être dans le fichier test.h et vous ne pouvez pas initialiser la variable globale dans le fichier d'en-tête.

Définition de fonction et utilisation de la variable globale dans le fichier test.c

si vous initialisez des variables globales dans l'en-tête, il y aura l'erreur suivante

définition multiple de "_ test" | obj\Debug\main.o: chemin\test.c | 1 | d'abord défini ici |

Seules les déclarations de variables globales dans le fichier d'en-tête, aucune initialisation ne devrait fonctionner.

J'espère que ça aide

À votre santé

6
Murad

Si vous utilisez Visual Studio, vous pouvez également faire "#pragma once" en haut du fichier d'en-tête pour obtenir la même chose que l'habillage "#ifndef ...". Certains autres compilateurs le supportent probablement aussi .. .. Cependant, ne le faites pas: D Restez avec le # ifndef-wrapping pour obtenir la compatibilité entre les compilateurs. Je voulais juste vous faire savoir que vous pouvez également faire #pragma une fois, car vous rencontrerez probablement un peu cette déclaration lors de la lecture du code d'autres personnes.

Bonne chance

4
cwap

Y compris le fichier d'implémentation (test.c) le fait être ajouté à votre main.c et s'y conformer puis de nouveau séparément. Ainsi, la fonction test a deux définitions - une dans le code objet de main.c et une fois dans celle de test.c, ce qui vous donne une violation ODR. Vous devez créer un fichier d'en-tête contenant la déclaration de test et l'inclure dans main.c:

/* test.h */
#ifndef TEST_H
#define TEST_H
void test(); /* declaration */
#endif /* TEST_H */
4
dirkgently

Si vous avez ajouté test.c à votre projet Code :: Blocks, la définition sera vue deux fois - une fois via #include et une fois par l'éditeur de liens. Tu dois:

  • supprimer le #include "test.c"
  • créer un fichier test.h qui contient la déclaration: void test ();
  • inclure le fichier test.h dans main.c

4
anon