Можно ли избежать глобальных переменных в строго процедурной программе? - PullRequest
10 голосов
/ 29 апреля 2010

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

Ответы [ 8 ]

12 голосов
/ 29 апреля 2010

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

6 голосов
/ 29 апреля 2010

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

3 голосов
/ 29 апреля 2010

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

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

3 голосов
/ 29 апреля 2010

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

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

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

// System.h

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

// System.c

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

и т.д ..

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

2 голосов
/ 29 апреля 2010

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

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

0 голосов
/ 29 апреля 2010

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

0 голосов
/ 29 апреля 2010

В качестве примера можно попробовать создать с помощью 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

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

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

0 голосов
/ 29 апреля 2010

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

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

(я бы посоветовал взглянуть на источники Linux)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...