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

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

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

// 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 ответов


фокус в том, что ... файл 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"

другие .с файлы:

#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"


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

фу.h:

#ifndef FOO_H
#define FOO_H

extern int foo;

#endif

фу.c:

#include "foo.h"

int foo = 0;

бар.c:

#include "foo.h"
#include <stdio.h>
int main(int argc, char** argv)
{
    printf("foo:%d\n",foo);
    return 0;
}

материал макроса глуп для этого. Просто положите

extern int myGlobal;

в вашем заголовочном файле и в одном .C файл (обычно с тем же именем, что и у .h файл), put

int myGlobal;

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


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

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


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

// 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 вы не можете избежать их (особенно в коде, унаследованном кем-то), но лучше всего держать их вне.

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

// 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"

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

#define FOO_C_

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

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

С foo.ч быть:

#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_