SapegoAL 0 14 октября, 2009 Опубликовано 14 октября, 2009 · Жалоба Раньше у меня не было таких проблем. Обычно создавал группу файлов. Как правило все файлы были достаточно обособленными и я их объединял на этапе линковки. Если были групповые общие объявления, то я их делал в main, а в других объявлял как extern. Проблема возникла в одном проекте. Он получил развитие и теперь существует в нескольких реинкарнациях с различными модификациями и процами. Тем не менее там есть очень крупные общие блоки. Столкнувшись, с проблемой поддержки - пришёл к необходимости общую часть исходников выделить в отдельные файлы/процедуры. А иначе, при внесении изменений приходилось править все проекты. Выделил и переписал, с учётом унификации. А теперь вопрос. Эти блоки используют общие глобальные переменные. Как их правильно объявить, чтобы было удобнее использовать и поддерживать, а также было меньше разной писанины? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 14 октября, 2009 Опубликовано 14 октября, 2009 · Жалоба Может стоит объединить переменные в глобальную структуру? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 14 октября, 2009 Опубликовано 14 октября, 2009 · Жалоба Не знаю правда ли, но я недавно прочел такую вещь: 56. Не захламляйте область глобальных имен Беспорядок в области глобальных имен является характерной проблемой для среды групповой разработки. Вам не очень понравится спрашивать разрешение от каждого участника группы каждый раз, когда вы вводите новый идентификатор. Поэтому: • Локальная переменная всегда более предпочтительна, чем член класса. • Член класса всегда более предпочтителен, чем статическая глобальная переменная. • Статическая глобальная переменная всегда более предпочтительна, чем настоящая глобальная переменная. Статический глобальный идентификатор не экспортируется из файла .c, поэтому он невидим из других модулей. Применяйте модификатор static к как можно большему числу глобальных идентификаторов (переменным и функциям). Ключ доступа private в определении класса еще лучше. Идентификатор, определенный локально внутри подпрограммы, лучше всех, потому что он изолирован от всех других функций в программе. Вывод: избегайте препроцессора. Так как у макроса такая большая область видимости, то он, по сути, то же самое, что и глобальная переменная. Ален И. Голуб Правила программирования на Си и Си++ А ещё где-то он писал, что за более чем 20летнюю практику программирования он может сказать, что реально обычно требуется пять-десять действительно глобальных переменных на большой проект. Поэтому Вам следует пересмотреть тактику проектирования модулей и, возможно всё станет куда более прозрачно. P.S. книгу тоже к прочтению рекомендую, хотя тут прозвучала мысль, что она уже очень старая и некоторые вещи сейчас могут утратить актуальность...это тоже похоже на правду. В общем её(как и всё в этой жизни) нужно использовать с умом :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 14 октября, 2009 Опубликовано 14 октября, 2009 · Жалоба Может стоит объединить переменные в глобальную структуру? Проект достаточно крупный. Переменных много. В том числе и структуры тоже есть. А ещё где-то он писал, что за более чем 20летнюю практику программирования он может сказать, что реально обычно требуется пять-десять действительно глобальных переменных на большой проект. В общем так обычно у меня и было. Поэтому вопрос и не возникал. А тут специфика. Представте что модуль выполняет обработку. А-В-С. Причём часть тела модуля B является специфической для разных проектов. Если не резать, то всё нормально, но тогда придётся поддерживать 4 разных проекта. Но часть B является незначительной по сравнению с объёмом самого проекта. Остальные части удалось формализовать. Частично пришлось переписать с прицелом на "универсальность". В результате со всеми проектами можно работать по единым правилам. А то раньше - где-то подправишь - в другом вылазит. За книгу спасибо, попробую почитать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sigmaN 0 14 октября, 2009 Опубликовано 14 октября, 2009 · Жалоба Ну тут, ИМХО, кроме Вас никто не решит проблему. Я иногда по два-три раза переписываю модули. И причиной является именно неудачное сцепление с остальными :) Хотя на меня ровняться не стоит особо - я ещё относительно неопытный программист. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Faradey 0 14 октября, 2009 Опубликовано 14 октября, 2009 · Жалоба как вариант, объедините специфические "переменные" в группы и передавайте в исп. ф-ции указатель на них: extern MyType my_type; extern int f1( void *p ); ... int res = f1( ( void *)&my_type ); Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
kurtis 0 14 октября, 2009 Опубликовано 14 октября, 2009 · Жалоба В общем так обычно у меня и было. Поэтому вопрос и не возникал. А тут специфика. Представте что модуль выполняет обработку. А-В-С. Причём часть тела модуля B является специфической для разных проектов. Если не резать, то всё нормально, но тогда придётся поддерживать 4 разных проекта. Но часть B является незначительной по сравнению с объёмом самого проекта. Остальные части удалось формализовать. Частично пришлось переписать с прицелом на "универсальность". В результате со всеми проектами можно работать по единым правилам. А то раньше - где-то подправишь - в другом вылазит. Попробуй-те использовать С++ ! Пишете какой-то виртуальный базовый класс-родитель, который имеет только интерфейс, никакого кода, а потом наследуете каждый конкретный модуль от базового класса и пишете свой, специфический для данного модуля код (т.е. будет класс_А, класс_Б и тд). Константы и перечисления можно запрятать в класс и никто снаружи их не будет видеть. Ну а дальше уже пишите технологию, которая через интерфейс базового класса работает с Вашими модулями. Ну и для пущей уверенности, запихать все по своим пространствам имен (namespace). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 14 октября, 2009 Опубликовано 14 октября, 2009 · Жалоба Попробуй-те использовать С++ ! Похоже что было бы оптимально. Там и так уже практически готовая работа с объектами. Но всё равно надо переписывать, а это сейчас влом. Отладка займёт слишком много времени. Проект вылизывался года полтора, чтобы ни сучка ни задоринки. Я просто думал, что существуют какие-то "стандартные решения" на этот случай. Всем ответившим - спасибо. :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 14 октября, 2009 Опубликовано 14 октября, 2009 · Жалоба Константы и перечисления можно запрятать в класс и никто снаружи их не будет видеть.... Для собственно данных существенных преимуществ перед банальным запихиванием всего вышеперечисленного в банальную сишную структуру нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DimaG 0 15 октября, 2009 Опубликовано 15 октября, 2009 · Жалоба Ранее тоже столкнулся с тем, что большая часть кода активно используется в нескольких проектах. Соответственно выделил ее в некоторый фреймворк. Фреймворк тоже состоит из двух частей - платформонезависимой и платформозависимой. Все логически законченные модули обозвал как сервисы, для общения между сервисами написал систему передачи сообщений (с интересной мне особенностью - сервис передающий сообщение ничего не знает о том сервисе (сервисах), которые его получат. В частном случае их (получаетелей) вообще может не быть. Чем-то напоминает идеологию шины CANbus (каждое сообщение характеризуется не адресом получателя, а своим собственным идентификатором). Все это написано на С++ Если будет интерес - могу выложить код Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 67 15 октября, 2009 Опубликовано 15 октября, 2009 · Жалоба Попробуй-те использовать С++ ! Пишете какой-то виртуальный базовый класс-родитель, Вы хотели сказать "абстрактный базовый класс"? Похоже что было бы оптимально. Там и так уже практически готовая работа с объектами. Тоже за С++. Только не уверен, что тут нужна иерархия полиморфных классов (т.е. с виртуальными функциями). Мне кажется, что тут достаточно будет просто определить интерфейсы (как там что с чем взаимодействует), и из этого уже автоматом получаются интерфейсы классов - фукнции-члены в public части класса. Все, далее представление и реализации классов можно будет спокойно менять - пока интерфейсы неизменны, совместимость будет на месте. Таким образом можно отделить интерфейсы от реализации. В объектом программирование оно называется инкапсуляцией. Чтобы не разрабатывать заново код, лучше всего (и проще всего) написать классы-обертки, в которых определены интерфейсы (открытые функции-члены), вызывающие уже существующий отлаженный код. Таким образом, взаимодействие снаружи будет четко определено, вся реализация будет внутри и не видна наружу. Для собственно данных существенных преимуществ перед банальным запихиванием всего вышеперечисленного в банальную сишную структуру нет. Данные - они не сами по себе, с ними код работает. И данные лучше спрятать подальше от произвольного доступа, а наружу выдать только допустимые методы работы с данными. Поэтому данные надо не в структуру спрятать, а в класс, в private секцию. Разница с сишной структурой будет более, чем значительна. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flexz 0 15 октября, 2009 Опубликовано 15 октября, 2009 · Жалоба Вобщем-то, все что вы предлагаете можно и на С реализовать, не применяя классы. Абстрактный базовый класс? прототипы функций в .h-файле private-секция? static структура. Нужно несколько экземпляров одинакового модуля в рамках одного проекта? Передавайте указатель на эту структурку, преобразовав его к void*, дабы вызывающий код не лазил куда не следует (идиома pimpl). Несколько реализаций одного базового (абстрактного) класса, в данном конктретном случае, как я понял, не нужны, но и их при желании можно реализовать с помощью структуры с набором указателей на функции. ИМХО в данном случае это лучше, т.к. перетащить большой готовый проект с С на С++ в одно действие не выйдет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
DimaG 0 15 октября, 2009 Опубликовано 15 октября, 2009 · Жалоба ИМХО в данном случае это лучше, т.к. перетащить большой готовый проект с С на С++ в одно действие не выйдет. Никто не спорит, что можно заниматься объектным программированием на Си, Другое дело - насоклько это удобно (ИМХО - как ездить на велосипеде без педалей. Можно, но пешком быстрее)) ). Насчет приведения к (void*) - это путь для всевозможных трудноуловимых ошибок, тк рано или поздно будет передан не тот объект, который ожидаем :) Одно из достоинств С++ - строгий контроль за типом данных. Да простейший пример - очереди. Попробуйте реализовать универсальную очередь на Си и на С++, и почувствуйте разницу :) Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
dxp 67 15 октября, 2009 Опубликовано 15 октября, 2009 · Жалоба Вобщем-то, все что вы предлагаете можно и на С реализовать, не применяя классы. Абстрактный базовый класс? прототипы функций в .h-файле private-секция? static структура. Нужно несколько экземпляров одинакового модуля в рамках одного проекта? Передавайте указатель на эту структурку, преобразовав его к void*, дабы вызывающий код не лазил куда не следует (идиома pimpl). Не берусь судить в целом, но советовать использовать void* ни в коем случае не стал бы. Работа через void* - это хак, и в если его где и оправдано применять, так не от хорошей жизни. Случаи использования void* надо сводить к минимуму, в идеале - к нулю. Несколько реализаций одного базового (абстрактного) класса, в данном конктретном случае, как я понял, не нужны, но и их при желании можно реализовать с помощью структуры с набором указателей на функции. ИМХО в данном случае это лучше, т.к. перетащить большой готовый проект с С на С++ в одно действие не выйдет. Может и лучше. Но если уж оставаться на С, то и концепции С++ лучше не тащить, от них при ручной реализации будет больше проблем, чем пользы. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Flexz 0 15 октября, 2009 Опубликовано 15 октября, 2009 · Жалоба Насчет приведения к (void*) - это путь для всевозможных трудноуловимых ошибок, тк рано или поздно будет передан не тот объект, который ожидаем Это элементарно контролируется сигнатурой и/или sizeof. И вообще меня неправильно поняли - я не предлагаю тащить в С концепции С++, а лишь провожу аналогии - это все там и так есть, просто приглядитесь повнимательнее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться