Включая заголовочный файл C с большим количеством глобальных переменных - PullRequest
6 голосов
/ 19 мая 2010

У меня есть включаемый файл с более чем 100 глобальными переменными. Он используется в библиотеке, но некоторые программы, с которыми я связываю библиотеку, также должны иметь доступ к глобальным переменным.

Как это было построено:

// In one library .c file
#define Extern

// In the programs that use the globals
#define Extern extern

// In the .h file
Extern int a,b,c;

Мне было трудно понять, почему оригинальный программист сделал это, поэтому я удалил это определение Extern. Теперь я думаю, что понимаю вещь о TU с помощью stackoverflow: 1 , 2 , 3 .

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

Должен ли я вернуться к этому #define Extern voodoo?

Ответы [ 8 ]

8 голосов
/ 20 мая 2010

Хитрость в том, что файл .h используется двумя различными способами - он используется как обычный файл .h, где все глобальные переменные объявлены extern, и также используется для определения * 1003. * сами глобалы (без extern). Это уродливый хак, но вы можете понять, почему кто-то счел это необходимым, если у вас большое количество глобальных переменных (верный признак очень плохого дизайна программного обеспечения!).

В любом случае, есть несколько более элегантное решение - вы можете поместить все глобальные переменные в единую глобальную структуру, например,

//
// globals.h
//

typedef struct {
    int a;
    int b;
    // ...
    int z;
} Globals;

extern Globals globals; // declaration

-

//
// globals.c
//

#include "globals.h"

Globals globals; // definition

-

Тогда, когда вам нужно обратиться к глобальному, это, например, globals.a вместо просто a, что может показаться неудобством, но это, возможно, яснее и более управляемо, чем просто разбросанные по всему коду голые глобалы.

6 голосов
/ 19 мая 2010

Неправильно определять Extern в каждом файле .c. Возможно, лучше удалить его, но вам нужно как-то заменить эту функцию. Один из подходов состоит в том, что вы можете использовать #define в файле .c, который должен определять эти глобальные переменные. Это определение будет указывать .h не выходить за пределы глобальных переменных.

Например: Одна библиотека .c файл:

#define FOO_LIBRARY_C
#include "foo_library.h"

Другие файлы .c:

#include "foo_library.h"

foo_library.h:

#ifdef FOO_LIBRARY_C
int a,b,c
#else
extern int a,b,c
#endif

или

#ifdef FOO_LIBRARY_C
#define GLOBAL_PREFIX
#else 
#define GLOBAL_PREFIX extern
#endif

GLOBAL_PREFIX int a,b,c

Это уменьшает необходимость определять одно и то же в каждом исходном файле (кроме одного) и помогает уменьшить количество ошибок. Я также не назвал бы это Экстерном, поскольку это может только вызвать путаницу, поскольку это может или не может быть "внешним"

3 голосов
/ 19 апреля 2011

Макросы глупы для этого. Просто поставь

extern int myGlobal;

в заголовочном файле и в ОДНОМ файле .c (обычно с тем же именем, что и у файла .h), поместите

int myGlobal;

Не нужно беспокоиться об этом уровне "дублирования".

3 голосов
/ 19 мая 2010

Может быть, я тоже что-то упускаю, но я ВСЕГДА использую защиту включения для всех создаваемых мной заголовочных файлов:

foo.h:

#ifndef FOO_H
#define FOO_H

extern int foo;

#endif

foo.c:

#include "foo.h"

int foo = 0;

bar.c:

#include "foo.h"
#include <stdio.h>
int main(int argc, char** argv)
{
    printf("foo:%d\n",foo);
    return 0;
}
2 голосов
/ 19 мая 2010

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

По сути, вы должны объявить переменные в файле .h и определить их в файле .c. Не считайте это дублированием кода - я думаю, что изменение точки зрения - лучшее, что вы можете здесь сделать :). Вы можете написать больше строк кода, но они будут читабельны: D.

1 голос
/ 05 июня 2011

В больших программах очень важно иметь одну строку для объявления и определения глобальной переменной. Следовательно, описанный выше макроподход является правильным способом решения проблемы.

// globals.h 
#ifndef GLOBALS_H 
#define GLOBALS_H  
#ifndef EXTERN 
#define EXTERN extern 
#endif
EXTERN int i; 
#endif  

// globals.c 
#define EXTERN 
#include "globals.h" 
0 голосов
/ 20 мая 2010

Как правило - не используйте глобальные переменные. Иногда вам нужно использовать статические переменные в файле, но лучше всего их вообще избегать:

  • Нельзя правильно выполнить модульное тестирование кода, который содержит глобальные переменные
  • Нет чистого разделения между модулями, которое может вызвать проблемы с изоляцией ошибок
  • Обычно не потокобезопасен. Вы должны обернуть их мьютексами и т. Д. Если вы хотите использовать потоки (как правило, все лучше и лучше, поскольку мы получаем все больше и больше ядер), вы можете столкнуться с проблемами с записываемым общим состоянием.

Иногда в C вы не можете избежать их (особенно в коде, унаследованном кем-то), но лучше всего их не пускать.

Что касается объявления - это может быть полезно в таком случае:

// globals.h

#ifndef GLOBALS_H
#define GLOBALS_H

#ifndef EXTERN
#define EXTERN extern
#endif

EXTERN int i;
#endif

// globals.c
#define EXTERN
#include "globals.h"
0 голосов
/ 20 мая 2010

Хотя это может поначалу раздражать, но это поможет вам избежать необходимости вводить что-либо дважды или вообще забыть включить что-либо в файл .c. Я видел:

#define FOO_C_

#include "foo.h"
#include "bar.h"

int foo_doit(int a, int b, int c) {
...
}

с foo.h, являющимся:

#ifndef FOO_H_
#define FOO_H_

#ifdef FOO_C_
#define GLOBAL
#define DECLARE( type, name, value) type name = value
#else
#define GLOBAL extern
#define DECLARE( type, name, value) extern type name;
#endif

GLOBAL int foo_doit(int a, int b, int c);
GLOBAL int foo_it; // uninitialized global variable
DECLARE(char, that[], "that");

// and sometimes using:
#ifdef FOO_C_
char word[] = letters;
#else
extern char word[];
#endif


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