2009-03-23 2 views
25

Я новичок C, и я просто пытался написать консольное приложение с кодом :: Blocks. Вот (упрощенный) код: main.c:Как предотвратить несколько определений в 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() {} 

Когда я пытаюсь построить эту программу, она дает следующие ошибки:

 
*path*\test.c|1|multiple definition of `_ test'| 
obj\Debug\main.o:*path*\test.c|1|first defined here| 

Нет никакого способа, чтобы я многократно определял тест (хотя я не знаю, откуда этот символ подчеркивания), и кажется маловероятным, что определение как-то включается дважды. Это все код.

Я исключил, что эта ошибка вызвана конфликтом с именованием других функций или файлов, называемых test или test.c. Обратите внимание, что множественное и первое определение находятся в одной строке в одном файле.

Кто-нибудь знает, что вызывает это и что я могу с этим поделать? Благодаря!

ответ

66

Вы компилировать исходный код test.c дважды:

  • Первый раз при компиляции test.c сам,
  • Второй раз при компиляции main.c, которая включает в себя все test.c источник.

Что вам нужно в main.c для того, чтобы использовать функцию test() является простой декларацией, а не его определение. Это достигается путем включения файла в test.h заголовка, который содержит что-то вроде:

void test(void); 

Это сообщает компилятору, что такая функция с входными параметрами и возвращаемым типом существует. Что делает эта функция (все внутри { и }) остается в вашем файле test.c.

В main.c, заменить #include "test.c" на #include "test.h".

Последняя точка: с более сложными программами вы столкнетесь с ситуациями, когда заголовочные файлы могут быть включены несколько раз. Чтобы предотвратить это, источники заголовков иногда обнесены конкретными определениями макросов, например:

#ifndef TEST_H_INCLUDED 
#define TEST_H_INCLUDED 

void test(void); 

#endif 
+0

Имена, такие как _TEST.H_, которые начинаются с подчеркивания и заглавной буквы, являются незаконными в коде пользователя C - они зарезервированы для разработчиков компилятора. – 2009-03-23 10:13:44

+0

Вы должны предоставить информацию о параметрах test() в файле заголовка, то есть void test(); -> void test (void); – aib

+0

Я просто взял интерфейс, предложенный в вопросе, но вы правы: я обновляю свой ответ. – mouviciel

9

Вы не должны включать другие исходные файлы (* .c) в файлы .c. Я думаю, вы хотите иметь заголовок ( .h) файл с ДЕКЛАРАЦИЕЙ тестовой функции и иметь ОПРЕДЕЛЕНИЕ в отдельном файле .c.

Ошибка вызвана несколькими определениями функции тестирования (один в test.c и других в main.c)

4

Включая файл реализации (test.c) приводит к его присоединяемый к вашему main.c и выполнял там и снова раздельно. Таким образом, функция test имеет два определения: один в объектном коде main.c и один раз в test.c, что дает вам нарушение ODR. Вам нужно создать файл заголовка, содержащего декларацию test и включить его в main.c:

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

Если вы добавили test.c в свой кодекс :: Blocks проекта, определение будет видно дважды - один раз с помощью #include и один раз компоновщиком. Вам нужно:

  • удалить #include "test.c"
  • создать файл, который содержит test.h декларации: недействительного теста();
  • включить файл test.h в main.c

20

Подчеркивание положить туда компилятором и используется линкера. Основной путь:

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

Итак, ваша основная программа должна включать заголовочный файл для тестового модуля, который должен состоять только из деклараций, таких как прототип функции:

void test(void); 

Это позволяет компилятору знаете, что он существует, когда main.c скомпилирован, но фактический код находится в test.c, затем test.o.

Это связующая фаза, соединяющая два модуля.

Включая test.c в main.c, вы определяете функцию test() в main.o. Предположительно, вы затем связываете main.o и test.o, оба из которых содержат функцию test().

+1

Up-голосований на хорошую схему. –

+1

Еще одно голосование за красивую диаграмму ASCII. –

4

Если вы используете Visual Studio вы можете также сделать «#pragma один раз» в верхней части headerfile, чтобы достичь того же как «#ifndef ...» - обертывание. Некоторые другие компиляторы, вероятно, поддерживают его также. .. Однако не делайте этого: D Придерживайтесь # ifndef-wrapping для достижения совместимости с несколькими компиляторами. Я просто хотел сообщить вам, что вы также можете сделать #pragma один раз, так как вы, вероятно, встретите это утверждение совсем немного, читая код других людей.

Удачи вам

5

У меня была аналогичная проблема, и я решил ее следующим образом.

Решить следующим образом:

объявление прототипа функции и глобальные переменные должен быть в test.h файла, и вы не можете инициализировать глобальные переменные в файле заголовок.

Определение функции и использование глобальной переменной в файле test.c

, если инициализировать глобальные переменные в заголовке будет иметь следующие ошибки

множественным определение `_ тест '| obj \ Debug \ main.o: путь \ test.c | 1 | сначала определен здесь |

Просто объявления глобальных переменных в файле заголовка, никакая инициализация не должна работать.

Надеется, что это помогает

Приветствия

Смежные вопросы