Перейти к содержанию
    

Раньше у меня не было таких проблем. Обычно создавал группу файлов. Как правило все файлы были достаточно обособленными и я их объединял на этапе линковки. Если были групповые общие объявления, то я их делал в main, а в других объявлял как extern.

 

Проблема возникла в одном проекте. Он получил развитие и теперь существует в нескольких реинкарнациях с различными модификациями и процами. Тем не менее там есть очень крупные общие блоки. Столкнувшись, с проблемой поддержки - пришёл к необходимости общую часть исходников выделить в отдельные файлы/процедуры. А иначе, при внесении изменений приходилось править все проекты. Выделил и переписал, с учётом унификации.

 

А теперь вопрос.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не знаю правда ли, но я недавно прочел такую вещь:

56. Не захламляйте область глобальных имен

Беспорядок в области глобальных имен является характерной проблемой

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

разрешение от каждого участника группы каждый раз, когда вы вводите

новый идентификатор. Поэтому:

• Локальная переменная всегда более предпочтительна, чем член класса.

• Член класса всегда более предпочтителен, чем статическая глобальная

переменная.

• Статическая глобальная переменная всегда более предпочтительна,

чем настоящая глобальная переменная.

Статический глобальный идентификатор не экспортируется из файла .c,

поэтому он невидим из других модулей. Применяйте модификатор

static к как можно большему числу глобальных идентификаторов

(переменным и функциям). Ключ доступа private в определении класса

еще лучше. Идентификатор, определенный локально внутри

подпрограммы, лучше всех, потому что он изолирован от всех других

функций в программе.

Вывод: избегайте препроцессора. Так как у макроса такая большая

область видимости, то он, по сути, то же самое, что и глобальная

переменная.

Ален И. Голуб Правила программирования на Си и Си++

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

Поэтому Вам следует пересмотреть тактику проектирования модулей и, возможно всё станет куда более прозрачно.

 

P.S. книгу тоже к прочтению рекомендую, хотя тут прозвучала мысль, что она уже очень старая и некоторые вещи сейчас могут утратить актуальность...это тоже похоже на правду.

В общем её(как и всё в этой жизни) нужно использовать с умом :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может стоит объединить переменные в глобальную структуру?

Проект достаточно крупный. Переменных много. В том числе и структуры тоже есть.

 

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

В общем так обычно у меня и было. Поэтому вопрос и не возникал. А тут специфика.

Представте что модуль выполняет обработку. А-В-С. Причём часть тела модуля B является специфической для разных проектов.

Если не резать, то всё нормально, но тогда придётся поддерживать 4 разных проекта. Но часть B является незначительной по сравнению с объёмом самого проекта. Остальные части удалось формализовать. Частично пришлось переписать с прицелом на "универсальность". В результате со всеми проектами можно работать по единым правилам. А то раньше - где-то подправишь - в другом вылазит.

 

За книгу спасибо, попробую почитать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ну тут, ИМХО, кроме Вас никто не решит проблему.

Я иногда по два-три раза переписываю модули. И причиной является именно неудачное сцепление с остальными :)

Хотя на меня ровняться не стоит особо - я ещё относительно неопытный программист.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

как вариант, объедините специфические "переменные" в группы и передавайте в исп. ф-ции указатель на них:

extern MyType my_type;
extern int f1( void *p );

...

int res = f1( ( void *)&my_type );

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В общем так обычно у меня и было. Поэтому вопрос и не возникал. А тут специфика.

Представте что модуль выполняет обработку. А-В-С. Причём часть тела модуля B является специфической для разных проектов.

Если не резать, то всё нормально, но тогда придётся поддерживать 4 разных проекта. Но часть B является незначительной по сравнению с объёмом самого проекта. Остальные части удалось формализовать. Частично пришлось переписать с прицелом на "универсальность". В результате со всеми проектами можно работать по единым правилам. А то раньше - где-то подправишь - в другом вылазит.

 

Попробуй-те использовать С++ !

Пишете какой-то виртуальный базовый класс-родитель, который имеет только интерфейс, никакого кода, а потом наследуете каждый конкретный модуль от базового класса и пишете свой, специфический для данного модуля код (т.е. будет класс_А, класс_Б и тд). Константы и перечисления можно запрятать в класс и никто снаружи их не будет видеть. Ну а дальше уже пишите технологию, которая через интерфейс базового класса работает с Вашими модулями. Ну и для пущей уверенности, запихать все по своим пространствам имен (namespace).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробуй-те использовать С++ !

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

 

Я просто думал, что существуют какие-то "стандартные решения" на этот случай.

 

Всем ответившим - спасибо.

:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Константы и перечисления можно запрятать в класс и никто снаружи их не будет видеть....

Для собственно данных существенных преимуществ перед банальным запихиванием всего вышеперечисленного в банальную сишную структуру нет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Ранее тоже столкнулся с тем, что большая часть кода активно используется в нескольких проектах. Соответственно выделил ее в некоторый фреймворк. Фреймворк тоже состоит из двух частей - платформонезависимой и платформозависимой.

 

Все логически законченные модули обозвал как сервисы, для общения между сервисами написал систему передачи сообщений (с интересной мне особенностью - сервис передающий сообщение ничего не знает о том сервисе (сервисах), которые его получат. В частном случае их (получаетелей) вообще может не быть. Чем-то напоминает идеологию шины CANbus (каждое сообщение характеризуется не адресом получателя, а своим собственным идентификатором).

 

Все это написано на С++

Если будет интерес - могу выложить код

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Попробуй-те использовать С++ !

Пишете какой-то виртуальный базовый класс-родитель,

Вы хотели сказать "абстрактный базовый класс"?

 

Похоже что было бы оптимально. Там и так уже практически готовая работа с объектами.

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

 

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

 

Для собственно данных существенных преимуществ перед банальным запихиванием всего вышеперечисленного в банальную сишную структуру нет.

Данные - они не сами по себе, с ними код работает. И данные лучше спрятать подальше от произвольного доступа, а наружу выдать только допустимые методы работы с данными. Поэтому данные надо не в структуру спрятать, а в класс, в private секцию. Разница с сишной структурой будет более, чем значительна.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Абстрактный базовый класс? прототипы функций в .h-файле

private-секция? static структура.

Нужно несколько экземпляров одинакового модуля в рамках одного проекта? Передавайте указатель на эту структурку, преобразовав его к void*, дабы вызывающий код не лазил куда не следует (идиома pimpl).

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

 

ИМХО в данном случае это лучше, т.к. перетащить большой готовый проект с С на С++ в одно действие не выйдет.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

ИМХО в данном случае это лучше, т.к. перетащить большой готовый проект с С на С++ в одно действие не выйдет.

 

Никто не спорит, что можно заниматься объектным программированием на Си, Другое дело - насоклько это удобно (ИМХО - как ездить на велосипеде без педалей. Можно, но пешком быстрее)) ).

 

Насчет приведения к (void*) - это путь для всевозможных трудноуловимых ошибок, тк рано или поздно будет передан не тот объект, который ожидаем :)

Одно из достоинств С++ - строгий контроль за типом данных. Да простейший пример - очереди. Попробуйте реализовать универсальную очередь на Си и на С++, и почувствуйте разницу :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Абстрактный базовый класс? прототипы функций в .h-файле

private-секция? static структура.

Нужно несколько экземпляров одинакового модуля в рамках одного проекта? Передавайте указатель на эту структурку, преобразовав его к void*, дабы вызывающий код не лазил куда не следует (идиома pimpl).

Не берусь судить в целом, но советовать использовать void* ни в коем случае не стал бы. Работа через void* - это хак, и в если его где и оправдано применять, так не от хорошей жизни. Случаи использования void* надо сводить к минимуму, в идеале - к нулю.

 

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

 

ИМХО в данном случае это лучше, т.к. перетащить большой готовый проект с С на С++ в одно действие не выйдет.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Насчет приведения к (void*) - это путь для всевозможных трудноуловимых ошибок, тк рано или поздно будет передан не тот объект, который ожидаем

Это элементарно контролируется сигнатурой и/или sizeof.

 

И вообще меня неправильно поняли - я не предлагаю тащить в С концепции С++, а лишь провожу аналогии - это все там и так есть, просто приглядитесь повнимательнее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...