внешняя переменная - PullRequest
0 голосов
/ 26 мая 2010

как использовать переменную, определенную в заголовке, и использовать их в нескольких исходных файлах, используя extern. Я получаю многократную ошибку определения.

1 Ответ

9 голосов
/ 26 мая 2010

Хорошее правило: «Не определять вещи в заголовочных файлах». Объявите все, что вы хотите, но определения должны быть ограничены не заголовками. объявление - это просто уведомление о том, что что-то существует. определение фактически определяет, что это такое.

Логическое обоснование этого руководства заключается в том, чтобы предотвратить именно ту ситуацию, с которой вы сталкиваетесь, - чтобы вещи определялись дважды (или более), поскольку заголовочные файлы включены в несколько модулей компиляции.

Чтобы избежать этого, вы можете использовать что-то вроде:

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;

Это плохая практика кодирования и совершенно ненужная.

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