У меня есть включать файл с 100 + глобальные переменные. Это используется в библиотеке, но некоторые программы, что я связываю lib для также доступа к globals.
Путем это было создано:
// 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;
Мне было нелегко понимать, почему исходный программист сделал это так, я удалил, которые определяют материал Экстерна. Теперь я думаю, что понимаю вещь о TU с помощью stackoverflow: 1, 2, 3.
Теперь я понимаю, что должен определить глобальные переменные в одном.c файле в библиотеке и использовать экстерна в.h файле. Проблема состоит в том, что я не хочу к дублирующему коду.
Я должен вернуться к этому #define вуду Экстерна?
Хитрость здесь заключается в том, что файл .h используется двумя различными способами - он используется как обычный файл .h, где все глобальные имена объявляются extern
, а также используется для определения самих глобальных (без 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
,это может показаться неудобством, но это, возможно, яснее и более управляемо, чем просто наличие голых глобальных глобалов, разбросанных по всему коду.
Определение 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
Это уменьшает необходимость определять одно и то же в каждом отдельном исходном файле (кроме одного) и может помогают уменьшить количество ошибок. Я бы также не назвал это Extern, так как это может вызвать путаницу, так как это может быть, а может и не быть "extern"
Возможно, я чего-то не понимаю, но я не вижу разницы между #define
и просто использованием ключевого слова extern
.
По сути, вы должны объявить переменные в .h-файле и определить их в .c-файле. Не считайте это дублированием кода - я думаю, что изменение точки зрения - это лучшее, что вы можете здесь сделать :). Вы можете написать больше строк кода, но они будут читабельны :D.
Возможно, я тоже что-то упускаю, но я ВСЕГДА использую защиту включения во всех создаваемых мной файлах заголовков:
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;
}
Практическое правило - не используйте глобальные переменные. Иногда вам нужно использовать статические переменные в файле, но лучше всего попытаться избежать их вообще:
Иногда в 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"
Поначалу это может раздражать, но зато помогает избежать необходимости вводить что-либо дважды или вообще не забывать включать что-то в файл .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_