Почему make file компилятора выдает ошибку, что функция переопределяется?
../data_module/data_process.c:8:5: error: redefinition of 'normalization' 8 | int normalization(double *data, int n) { | ^~~~~~~~~~~~~ In file included from ../data_module/data_process.h:4, from ../data_module/data_process.c:3: ../data_module/data_process.c:8:5: note: previous definition of 'normalization' with type 'int(double *, int)' 8 | int normalization(double *data, int n) { | ^~~~~~~~~~~~~ |
../data_module/data_process.c:8:5: error: redefinition of 'normalization' 8 | int normalization(double *data, int n) { | ^~~~~~~~~~~~~ In file included from ../data_module/data_process.h:4, from ../data_module/data_process.c:3: ../data_module/data_process.c:8:5: note: previous definition of 'normalization' with type 'int(double *, int)' 8 | int normalization(double *data, int n) { | ^~~~~~~~~~~~~
Функция иницилизиаруется 1 раз
Дополнительно:
Начну с самого начала и общих моментов.
Там же, вроде как, есть аж 3 стадии, перед тем как начать использовать функцию. Которые нужно правильно выполнить.
1) Объявление функции (краткая запись: возвращаемое значение, название, аргументы; вне тела основной программы (ф-и main())).
2) Реализация функции (тоже, что и выше, но уже с раскрытием ее содержимого, т. е. с описание ее функционала; вне тела основной программы (ф-и main())).
3) Вызов функции (собственно, ее запуск в теле основной программы (ф-и main())).
Также есть два типа файлов: исходник (*.c) и заголовочный файл ("хэдэр", *.h). У каждого свое назначение. В каждый записываются свои данные.
Мое предположение состоит в том, что вы где-то перемудрили. Например, написали реализацию и в заголовочном и в исходном - файлах. Или же, написали реализацию в заголовочном файле - вместо исходного. В общем, два раза одно и тоже или не там. Вот компиль и ругается. Чей-то вы мне, дескать, по десять разных функций с одинаковыми именами пишете. Не является ли запись одной функции - переопределенением (своего рода заменой) предыдущего ее варианта (функции с тем же именем, да еще и аргументами схожими).
Если что, я - не особо спец здесь, так что сильно не пинайте. :)
2) Реализация функции
А подскажи источник информации, где этот термин раскрывается.
Не буду в сотый раз упоминать (читай: рекламировать) литературу. В книге по языку программирования. Напишу своими словами, как я это понимаю.
Этот термин может называться не именно "реализация", но как-то так. Сейчас уж не вспомню гарантированно. Дело в том, что компилятор должен точно знать какую из функций вызвать. Если их указано две. Причем с одинаковой сигнатурой (объявление: название, аргументы). Он их не различает по содержимому (реализации).
Если есть необходимость получать разный тип обработки входных данных - в зависимости от самих входных данных, то делается это, предположим, так. Создается две функции с одинаковыми именами, но разными типами аргументов. Пусть, пользователь вводит числовые данные в консоли. В зависимости от типа данных (целый, вещественный), запускается своя функция. Которая производит некий расчет. Возвращает некий результат.
calculate(int i)
calculate(float i)
Реализация у каждой из функций, понятно, разная. Потому как есть некая разница в специфике обработки разных типов данных. Таким образом, у нас программа сама выбирает для обработки нужную функцию. Так сказать, автоматически. Хотя тоже самое можно было бы сделать и по-другому. Проверять тип входных данных и вызывать соответствующую функцию. Только непонятно, в переменную какого типа принимать данные с консольного ввода, если мы не знаем их тип заранее? Что надумает ввести человек - кто его знает.
calculate_int(int i)
calculate_float(float i)
А если предположить что у вас написано следующее (именно 2 раза).
calculate(int i)
calculate(int i)
То, понятное дело, компиль в непонятках: какую из функций вызывать. Он должен знать точно к чему обратиться. Это компьютер все-таки. :)
Вспомнилась школа: к доске пойдет..., к доске пойдет... Вася! Какой из двух? Он у нас не один. :)
Мой вопрос - это намек. Гадалок, экстрасенсов и беллетристов здесь итак хватает.
Похоже на какие-нибудь циклические инклуды.
У вас в data_process.h случайно не включается data_process.c?
Так делать не надо.
- включается, но ведь так положено?
да и другие точно так же перекрестно и не ругается - Алексей, Наверно ругается на первый попавшийся.
но ведь так положено
Нет. .c файлы никто нигде не включает. Только в каких-то особо извращенных случаях вроде сгенерированного кода.
Перекрестные включения не скомпилируются. Вообще циклические включения нельзя делать.
- Wataru,
1."Силами" компиляторами (просто командная строка gcc -Wall -Eextra -Werror файл) все собирается и работает без ошибок
2. ругаться начинает именно при работе с make файлом - Алексей, ну приводите тогда makefile. А заодно и все исходники.
- Алексей, нет, общепринятая практика, что есть .h-файл с заголовками (описания типов, функций итд) и .c с кодом. В одну кучу это собирают при линковке. Примерно так:
gcc -o file1.o -c file1.c gcc -o file2.o -c file2.c gcc -o main.o -c main.c gcc -o program file1.o file2.o main.o -lm -lawesomelib
gcc -o file1.o -c file1.c gcc -o file2.o -c file2.c gcc -o main.o -c main.c gcc -o program file1.o file2.o main.o -lm -lawesomelib
Также заголовочные файлы принято защищать от повторного включения так:
// внутри файла foobar.h #ifndef __FOOBAR_H #define __FOOBAR_H ... содержимое... #endif /* __FOOBAR_H */// внутри файла foobar.h #ifndef __FOOBAR_H #define __FOOBAR_H ... содержимое... #endif /* __FOOBAR_H */
Благодаря этому можно не париться, что другие заголовочные файлы включат тот же самый файл. Ведь __FOOBAR_H будет определено при первом включении.
- Да вы были правы.
действительно надо убрать 2ю ссылку и указывать при копиляции.
Спасибо
Да, в общем-то русским (английским) по черному написано - data_process.c включает data_process.h, который первым определил функцию normalization().
А потом сам data_process.c определил функцию normalization() чуть пониже - ессно компилятор выдает замечание о переопределении, ибо оно есть :)
Ответы:
Не юзайте using детки :)
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Чтобы разобраться в проблеме, необходимо понять, что означает ошибка "функция переопределяется" при компиляции с помощью make file компилятора.
Эта ошибка обычно возникает, когда у вас есть несколько определений одной и той же функции в разных файлах или модулях вашего проекта. Когда компилятор видит два или более определения одной и той же функции, он не может определить, какую из них использовать, и выдает ошибку переопределения.
Для решения этой проблемы необходимо убедиться, что каждая функция определена только один раз в вашем проекте. Проверьте все файлы, в которых есть определения функций, и убедитесь, что они не дублируются.
Также стоит обратить внимание на возможные конфликты имен функций. Если у вас есть функции с одинаковыми именами, но с разными параметрами или возвращаемыми значениями, компилятор может их воспринимать как переопределение функции.
Если вы используете сторонние библиотеки или фреймворки, убедитесь, что они не содержат дублирующихся определений функций.
Также стоит проверить правильность подключения файлов с определениями функций в вашем make file. Возможно, что файлы подключаются не в том порядке, из-за чего компилятор видит дублирующиеся определения.
Используйте ключевые слова extern или static при объявлении функций в заголовочных файлах, чтобы предотвратить их многократное определение при компиляции.
В итоге, следуя этим рекомендациям, вы сможете избежать ошибки "функция переопределяется" при компиляции вашего проекта с помощью make file компилятора.