Подтвердить что ты не робот

Как предотвратить несколько определений в 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. Обратите внимание, что множественное и первое определение находятся в одной строке в одном файле.

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

4b9b3361

Ответ 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 | сначала определено здесь |

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

Надеюсь, что это поможет

Приветствия