Каким-то образом я нарушаю правило одного определения

Я получаю ошибки с компоновщиком, такие как:

osd.o(.ndata+0x514):C:\Documents and Settings\Thomas\My Documents\PIC\dsPIC33FJ128GP802\On Screen Display\osd.c: multiple definition of `video_buff_vis_num'
main.o(.ndata+0x0):C:\Documents and Settings\Thomas\My Documents\PIC\dsPIC33FJ128GP802\On Screen Display\main.c: first defined here
osd.o(.ndata+0x515):C:\Documents and Settings\Thomas\My Documents\PIC\dsPIC33FJ128GP802\On Screen Display\osd.c: multiple definition of `video_buff_draw_num'
main.o(.ndata+0x1):C:\Documents and Settings\Thomas\My Documents\PIC\dsPIC33FJ128GP802\On Screen Display\main.c: first defined here
osd.o(.ndata+0x516):C:\Documents and Settings\Thomas\My Documents\PIC\dsPIC33FJ128GP802\On Screen Display\osd.c: multiple definition of `vid_format'
main.o(.ndata+0x2):C:\Documents and Settings\Thomas\My Documents\PIC\dsPIC33FJ128GP802\On Screen Display\main.c: first defined here
osd.o(.ndata+0x518):C:\Documents and Settings\Thomas\My Documents\PIC\dsPIC33FJ128GP802\On Screen Display\osd.c: multiple definition of `vid_line'
main.o(.ndata+0x4):C:\Documents and Settings\Thomas\My Documents\PIC\dsPIC33FJ128GP802\On Screen Display\main.c: first defined here

Это беспокоит меня, потому что в исходном коде я включил охрану вокруг единственного места, откуда могут появиться эти определения.

#ifndef OSD_H 
#define OSD_H 

// code here, including definitions for the above

#endif // OSD_H 

Это действует мне на нервы. Я почистил, восстановил и попробовал снова. Я даже начал новый проект с нуля с теми же файлами, и у меня точно такая же проблема! Кто-нибудь, пожалуйста, просветите меня, почему это не работает! :)

Компиляция с помощью PIC-GCC v3.23 (версия GCC для микроконтроллеров PIC24F/H и dsPIC30F/33F.)

Дайте мне знать, если кто-то хочет увидеть источники дополнительных файлов. Я не хотел перегружать эту страницу.


person Thomas O    schedule 19.07.2010    source источник
comment
Объявления находятся в файлах .h, определения — в файлах .c.   -  person Paul R    schedule 19.07.2010


Ответы (2)


Если вы включите этот заголовок более чем в 1 файл .c, у вас будет несколько определений. И у вас есть main.c и osd.c.

.h — это правильное место для объявлений функций и extern данных. Но для переменной вам придется выбрать один из исходных файлов. #defined охранники этого не меняют.

Также см. этот вопрос. И этот ответ описывает стандартный шаблон.

И еще немного пояснений/анализов:

1) Каждый .c исходный файл компилируется независимо. Охранники защищают только от двойного чтения заголовочного файла во время 1 компиляции.

2) Ошибка, которую вы получаете, является ошибкой компоновщика (не компилятора).

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

person Henk Holterman    schedule 19.07.2010
comment
Да и охрана здесь не поможет. - person Peter G.; 19.07.2010
comment
Итак, как я могу избежать этой проблемы? Я должен иметь определения osd.h в некоторых моих файлах. - person Thomas O; 19.07.2010
comment
Спасибо. Тогда я перенесу свои переменные в main.c. Было бы более уместно поместить их в osd.c, могу ли я это сделать? Спасибо за быстрый ответ! Я должен был спросить здесь, прежде чем тратить 3 часа на просмотр всего моего кода. Но, могу я спросить, почему здесь не удается включить охрану? Наверняка OSD_H определяется и тогда все хорошо, больше не включится? - person Thomas O; 19.07.2010
comment
.h — это правильное место для объявления функций. Реализации функций (кроме встроенных) также должны быть в файлах .c. @Thomas, он включен по одному на файл .c. Однако затем компоновщик связывает все полученные файлы .o вместе, и здесь возникает проблема. - person Matthew Flaschen; 19.07.2010
comment
@Thomas Компилятор компилирует каждый исходный файл отдельно, а затем связывает их. Защита включения предотвращает повторное включение одного и того же заголовка во время компиляции одного исходного файла, но он по-прежнему обрабатывается один раз для каждого исходного файла, включающего его (прямо или косвенно). - person Tyler McHenry; 19.07.2010
comment
Все кажутся переменными. У меня есть несколько встроенных функций. Никаких статичных. Как ни странно, PIC-GCC никогда ничего не встраивает... возможно, из-за нехватки места в ПЗУ, но это вопрос для другого дня. Спасибо всем. Я отмечу это как принятый ответ, когда это позволит мне (говорит, что мне нужно подождать 2 минуты). - person Thomas O; 19.07.2010
comment
Вы можете поместить переменные куда угодно, если они появляются только в одном исходном файле. Если другие исходные файлы должны использовать эти переменные, им следует дать объявление extern для переменной, возможно, в файле .h. - person Tyler McHenry; 19.07.2010

Что содержит ваш включаемый файл?

 int video_buff_vis_num;
 extern int video_buff_vis_num;

Первое или второе? Первый не определяет переменную, а выделяет для нее память, а второй просто говорит «где-то есть переменная с таким именем».

У вас должно быть только одно место, где он размещен, но у вас может быть много определений.

person Aaron Digulla    schedule 19.07.2010