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

У меня есть включать файл с 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 вуду Экстерна?

7
задан Community 23 May 2017 в 12:31
поделиться

6 ответов

Хитрость здесь заключается в том, что файл .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,это может показаться неудобством, но это, возможно, яснее и более управляемо, чем просто наличие голых глобальных глобалов, разбросанных по всему коду.

9
ответ дан 6 December 2019 в 06:35
поделиться

Определение 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"

6
ответ дан 6 December 2019 в 06:35
поделиться

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

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

2
ответ дан 6 December 2019 в 06:35
поделиться

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

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;
}
5
ответ дан 6 December 2019 в 06:35
поделиться

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

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

Иногда в 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
ответ дан 6 December 2019 в 06:35
поделиться

Поначалу это может раздражать, но зато помогает избежать необходимости вводить что-либо дважды или вообще не забывать включать что-то в файл .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_
-1
ответ дан 6 December 2019 в 06:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: