Можно ли избежать глобальных переменных в строго процедурной программе?

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

Ответ 1

Вы также можете написать объектно-ориентированный код в C. Вы не получаете все плюсы С++ и это уродливо, и вам нужно вручную передать этот указатель (я видел self, используемый для этого, чтобы чтобы он был совместим с С++), но он работает. Так что технически вам не нужно глобальное состояние в чистых процедурных языках по тем же причинам, что вам не нужны в объектно-ориентированных языках. Вам просто нужно передать состояние явно, а не косвенно, как в языках OO.

Ответ 2

В качестве примера рассмотрим, как функции ввода-вывода файлов в стандартной библиотеке C работают с указателем на объекты FILE, которые (в основном) непрозрачны. Или посмотрите, как OS API обрабатывают дескрипторы и т.д., Чтобы инкапсулировать информацию. Программа создает объекты, использует API, которые действуют на эти объекты, и закрывает/удаляет объекты - все используют прямой C.

Ответ 3

Все OO - это мышление и целая куча поддержки компилятора.

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

Например, у меня были функции/процедуры с префиксом их идентификатора модуля, причем первый параметр был связан с связанной структурой модуля.

// System.h

typedef struct _System
{
    struct _System *owner;
    LinkedList *elements;
} System;

// System.c

int System_FindName ( System * system, char *name)
{
..
}

и т.д..

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

Ответ 4

Глобальная переменная - это не что иное, как неявный аргумент процедуры. Сделайте это явным, и глобальная переменная уйдет.

Примечание: тот факт, что вы больше не используете глобальную переменную, не означает, что вы больше не используете глобальное состояние! То, что мы делали выше, было чисто синтаксическим преобразованием, семантика программы совсем не изменилась. Это как неконсолидируемое, немодульное, не-поточное, непараллелизуемое, как было раньше.

Ответ 5

Конечно. Просто объявите struct где-нибудь, выделите для него некоторую память, передайте указатель на выделенную память на функцию инициализации и отпустите. Просто передайте указатель на все функции, которые требуют использования структуры.

Хотя возникает вопрос о том, где вы храните указатель на данные, которые вы не хотите быть глобальными, а затем вы можете получить глобальный указатель; -)

Ответ 6

У вас могут быть переменные в стеке или в куче, которые будут существовать в течение всего срока службы программы.

Передача указателей структуры стиля объекта каждой функции - хороший способ иметь стиль кодирования OO C.

(я бы предложил посмотреть в источниках Linux)

Ответ 7

В качестве примера можно попробовать создать с помощью dia (инструмент диаграмм) простой класс (например, квадрат).
http://projects.gnome.org/dia/
http://dia-installer.de/index_en.html

Затем вы можете преобразовать этот класс в код C с помощью dia2code:
http://dia2code.sourceforge.net/

В частности, скажем, вы создали квадрат класса внутри диаграммы square.dia. Затем вы вводите:

$ dia2code -t c square.dia

... и вы увидите, что можно преобразовать любое объектно-ориентированное программирование в программу C без глобальных переменных. Исследуйте созданные файлы square.c и square.h

ПРИМЕЧАНИЕ. В Windows вам понадобится обходное решение для работы dia2code. Прежде чем использовать dia2code, измените square.dia на square.zip, разархивируйте его и переименуйте в виде square.dia

Ответ 8

Simple. Всякий раз, когда процедура обращается к глобальной переменной, вместо этого давайте эту переменную в качестве аргумента для процедуры, либо по значению, либо по ссылке или по указателю, либо любым вашим языком программирования. После этого больше нет необходимости, чтобы переменная была глобальной.