Хорошее правило: «Не определять вещи в заголовочных файлах». Объявите все, что вы хотите, но определения должны быть ограничены не заголовками. объявление - это просто уведомление о том, что что-то существует. определение фактически определяет, что это такое.
Логическое обоснование этого руководства заключается в том, чтобы предотвратить именно ту ситуацию, с которой вы сталкиваетесь, - чтобы вещи определялись дважды (или более), поскольку заголовочные файлы включены в несколько модулей компиляции.
Чтобы избежать этого, вы можете использовать что-то вроде:
myprog.h:
extern int myVar; // a declaration.
myprog.c:
#include "myprog.h"
int myVar = 7; // a definition.
otherbit.c:
#include "myprog.h"
int fn (void) {
myVar = 12;
return myVar;
}
Определение, приведенное выше, закончится только в myprog.o
, вы не получите другую копию в otherbit.o
, чтобы вызвать проблемы во время ссылки.
Если оставить в стороне правильную инкапсуляцию, эти глобальные переменные станут очень плохой идеей, вот как я это сделаю.
инкапсулированный способ сделать это будет примерно так:
myprog.h:
int getMyVar (void);
void setMyVar (int);
myprog.c:
#include "myprog.h"
static int myVar = 7;
int getMyVar (void) { return myVar; }
void setMyVar (int n) {
// Error checks on n here.
myVar = n;
}
otherbit.c:
#include "myprog.h"
int fn (void) {
setMyVar (12);
return getMyVar();
}
Инкапсуляция в основном скрывает информацию. Это означает, что вы должны раскрыть как можно меньше вашей внутренней работы, чтобы выполнить работу, чтобы вы не открыли себе возможность проникновения другого кода под покровы и недействительности ваших предположений (см. Ниже) или усложнить изменение вашей внутренней работы позже.
Классический пример - если вы хотите, чтобы переменная myVar
была ограничена диапазоном от 0 до 359 включительно (скажем, под углом). С инкапсуляцией вы можете просто использовать:
void setMyVar (unsigned int n) { myVar = n % 360; }
и никогда не нужно беспокоиться о его недействительности. Вы можете смело предположить, если не считать искажения памяти, что myVar
всегда будет в желаемом диапазоне. У вас не было бы такой уверенности, если бы какой-то жулик пользовательского кода мог войти и просто сделать:
myVar = 32767;
без вашего ведома. Вам нужно будет либо обработать значения за пределами желаемого диапазона, либо принудительно установить допустимый диапазон в начале всех ваших функций:
myVar = myVar % 360;
Это плохая практика кодирования и совершенно ненужная.