#ifndef
Включает защитные ограждения только на уровне единицы перевода (обычно это один исходный файл).
Если вы определите один и тот же объект дважды в двух единицах перевода, которые не будут исправлены включением охранников, но компоновщик будет жаловаться горько, когда вы попытаетесь объединить два объектных файла в один исполняемый файл.
Я подозреваю, что ваше положение сродни:
hdr.h:
#ifndef HDR_H
#define HDR_H
void rc(void);
int xyzzy;
#endif
prog1.c:
#include "hdr.h"
#include "hdr.h"
int main (void) { rc(); return xyzzy; }
prog2.c:
#include "hdr.h"
void rc(void) { xyzzy = 0; }
В такой ситуации, включаемые охранник предотвратит заголовок будучи дважды включен в prog1.c
, но он все равно будет включен как prog1.c
иprog2.c
, что означает, что каждый будет иметь копию xyzzy
.
Когда вы связываете их вместе, компоновщику это не понравится.
Решение не определить вещи в заголовках, но и просто объявить их там, оставляя определение для файла C:
hdr.h:
#ifndef HDR_H
#define HDR_H
int rc(void);
extern int xyzzy; // declare, not define
#endif
prog1.c:
#include "hdr.h"
#include "hdr.h"
int main (void) { rc(); return xyzzy; }
prog2.c:
#include "hdr.h"
int xyzzy; // define
int rc(void) { xyzzy = 0; }
Декларации вещи, как прототипы функций, внешних переменные, определения типов и так далее (упрощенно, вещи, которые объявляют что-то, существует, фактически не создавая «объект»).
Определение - это вещи, которые создают «объекты», например, не внешние переменные и т. Д.
Вы должны отследить, что «объект» определяется дважды (выход линкер должен иметь что-то вроде doubly-defined symbol 'xyzzy'
) и убедитесь, что это не определено в заголовке.
Спасибо за это объяснение. Очень полезное разъяснение –