Как предотвратить несколько определений в C?
Я новичок C, и я просто пытался написать консольное приложение с Code:: Blocks. Здесь (упрощенный) код:
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() {}
Когда я пытаюсь создать эту программу, она дает следующие ошибки:
*path*\test.c|1|multiple definition of `_ test'|
obj\Debug\main.o:*path*\test.c|1|first defined here|
Нет никакого способа, чтобы я многократно определял тест (хотя я не знаю, откуда встречается символ подчеркивания), и кажется маловероятным, что определение каким-то образом включается дважды. Это все код.
Я исключил, что эта ошибка вызвана конфликтом с именованием других функций или файлов, называемых test или test.c. Обратите внимание, что множественное и первое определение находятся в одной строке в одном файле.
Кто-нибудь знает, что вызывает это и что я могу с этим поделать? Спасибо!
Ответы
Ответ 1
Вы фактически скомпилируете исходный код 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
Ответ 2
Подчеркивание помещается туда компилятором и используется компоновщиком. Основной путь:
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().
Ответ 3
Вы не должны включать другие исходные файлы (*.c) в .c файлы. Я думаю, вы хотите иметь файл заголовка (.h) с DECLARATION тестовой функции и иметь его ОПРЕДЕЛЕНИЕ в отдельном файле .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 */
Ответ 5
Если вы добавили test.c в свой проект Code:: Blocks, определение будет видно дважды - один раз через #include и один раз компоновщиком. Вам необходимо:
- удалите #include "test.c"
- создать файл test.h, содержащий объявление: void test();
-
включают файл test.h в main.c
Ответ 6
Если вы используете Visual Studio, вы также можете сделать "#pragma once" в верхней части заголовочного файла, чтобы добиться того же, что и "#ifndef..." - wrapping. Возможно, некоторые другие компиляторы тоже поддерживают его.
.. Однако не делайте этого: D Придерживайтесь # ifndef-wrapping для достижения совместимости с несколькими компиляторами. Я просто хотел сообщить вам, что вы также можете сделать #pragma один раз, так как вы, вероятно, встретите это утверждение совсем немного, прочитав код других людей.
Удачи с ним
Ответ 7
У меня была аналогичная проблема, и я решил ее следующим образом.
Решите следующее:
Объявления прототипа функций и глобальная переменная должны быть в файле test.h, и вы не можете инициализировать глобальную переменную в файле заголовка.
Определение функции и использование глобальной переменной в файле test.c
если вы инициализируете глобальные переменные в заголовке, у него будет следующая ошибка
множественное определение `_ test '| obj\Debug\main.o: path\test.c | 1 | сначала определено здесь |
Просто объявления глобальных переменных в файле заголовка не должны инициализироваться.
Надеюсь, что это поможет
Приветствия