Будучи разработчиком, перенесенным и повышенным на OO, мне было любопытно услышать, как возможно избежать глобального состояния в процедурной программе.
Вы также можете писать объектно-ориентированный код на C. Вы не получите все плюсы C++, он уродлив, и вам придется вручную передавать этот указатель (я видел self
, используемый для этого, чтобы сделать его совместимым с C++), но он работает. Итак, технически, вам не нужно глобальное состояние в чистых процедурных языках по тем же причинам, по которым оно не нужно в объектно-ориентированных языках. Вы просто должны передавать состояние явно, а не неявно, как в ОО-языках.
Вы можете, например, попробовать создать с помощью dia (инструмент построения диаграмм) простой класс (например, квадрат). {{1} }
http://projects.gnome.org/dia/
http://dia-installer.de/index_en.html
Затем вы можете преобразовать этот класс в код C, используя dia2code: {{ 1}}
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
Вы можете иметь переменные в стеке или куче, которые будут существовать в течение всего срока службы программы.
Передача указателей на структуру стиля объекта каждой функции - хороший способ получить стиль кодирования OO C.
(я бы посоветовал поискать исходники linux)
Конечно. Просто объявите где-нибудь struct
, выделите для нее некоторую память, передайте указатель на выделенную память функции инициализации, и вперед. Просто передайте указатель на все функции, которые требуют использования структуры.
Хотя возникает вопрос, где вы храните указатель на данные, которые не должны быть глобальными, и тогда вы можете получить глобальный указатель; -)
Простой. Всякий раз, когда процедура обращается к глобальной переменной, вместо этого передайте эту переменную в качестве аргумента процедуры либо по значению, либо по ссылке, либо по указателю, либо по тому, что предоставляет ваш язык программирования. После этого переменная больше не должна быть глобальной.
Как Например, посмотрите, как функции файлового ввода-вывода в стандартной библиотеке C работают с указателем на объекты FILE
, которые (в основном) непрозрачны. Или посмотрите, как API ОС работают с дескрипторами и т. Д. Для инкапсуляции информации. Программа создает объекты, использует API-интерфейсы, которые воздействуют на эти объекты и закрывают / удаляют объекты - все с использованием прямого C.
Все ОО - это образ мышления и целая куча поддержки компилятора.
В большинстве языков вы можете добиться того же самого с помощью дисциплины, кодовых соглашений и передачи структур.
Например, я использовал функции/процедуры с префиксом их принадлежности к модулю, принимая первый параметр как связанную структуру модуля.
// System.h
typedef struct _System
{
struct _System *owner;
LinkedList *elements;
} System;
// System.c
int System_FindName ( System * system, char *name)
{
..
}
и т.д.
Я бы очень не хотел возвращаться к такому кодированию. Я очень рад, что мне не приходилось писать и отлаживать связанные списки по крайней мере 18 лет. Тогда было тяжело без интернета и сидения в углу холодной ярко освещенной комнаты с зелеными люминофорами, горящими в сетчатке...
Глобальная переменная - это не что иное, как неявный аргумент процедуры. Сделайте его явным , и глобальная переменная исчезнет.
Примечание: тот факт, что вы больше не используете глобальную переменную , не означает, что вы больше не используете глобальное состояние ! То, что мы сделали выше, было чисто синтаксическим преобразованием, семантика программы вообще не изменилась. Он такой же несоставимый, немодульный, не потокобезопасный, непараллелизируемый, как и раньше.