У меня сильный опыт работы с Java / Groovy, и я был назначен в команду, которая поддерживает довольно большую базу кода C для административного программного обеспечения.
Некоторые болевые точки, такие как работа с BLOB-объектами в базе данных или создание отчетов в PDF и Excel, были перенесены в веб-службу Java.
Однако, как разработчик Java, я немного смущен некоторыми аспектами кода:
- это многословно (особенно когда речь идет об «исключении»)
- есть много огромных методов (метод с более чем 2000 строк)
- нет сложных структур данных (я очень скучаю по List, Set и Map)
- нет разделения на проблемы (SQL радостно смешал весь код)
В результате я чувствую, что бизнес спрятан в тоннах технического кода, и мой мозг, сформированный с помощью Object Oriented и щепотки функционального программирования, не чувствует себя спокойно.
Хорошая сторона проекта в том, что код прост: нет фреймворка, нет манипуляций с байт-кодом во время выполнения, нет AOP. И сервер может одновременно отвечать более чем 10000 пользователям на одной машине, используя меньше памяти, чем нужно Java, чтобы выплюнуть «привет мир».
Я хочу научиться писать код на C в соответствии с общепринятыми современными принципами. Существуют ли общепринятые принципы того, как современный С должен быть написан и структурирован?
Нечто похожее на книгу «Эффективная Java», но для C.
Изменить с учетом ответов и комментариев:
- Я постараюсь адаптировать свое мышление к коду C, а не пытаться отразить его в ООП.
- Я начал сканировать и прочитать рекомендуемые руководства по стилю кодирования из комментария (Стандарты кодирования GNU и Стиль кодирования ядра Linux).
- Затем я попытаюсь предложить этот стиль кода моим коллегам. Самым сложным может быть убедить коллег в том, что огромный метод можно разбить на более мелкие части и что с помощью метода можно избежать повторения тех же четырех строк кода обработки ошибок.
источник
Ответы:
Я могу прочитать из вашего вопроса, проблема не в том, что код старый C, а просто плохое программирование. Большинство проблем, о которых вы упомянули, таких как многословие, огромные линейные функции 2000+ или отсутствие разделения интересов, применимы к любому языку, C или Java.
Детальность упоминалась в контексте обработки ошибок. Вы не предоставили пример, поэтому я могу только напомнить, что код обработки ошибок - это тоже код . Нет повода для повторяющихся разделов стандартного кода. Фактор это из; либо в функцию, либо (если не стоит создавать отдельную функцию) создайте
goto Error;
шаблон и переместите обработку ошибок и очистку ресурса вError:
раздел внизу функции.Если проходя ошибку вверх по цепочке вызовов , как представляется, проблема, спросите себя: это функция там действительно нужно знать какой - нибудь парень , здесь была проблема? Механизмы исключений, встроенные в язык, упрощают это, но в целом лучше обрабатывать исключения рано (на любом языке), чтобы условие ошибки не загрязняло логику высокоуровневого кода. И если функция действительно должна знать, есть способы эмулировать исключения с помощью
setjmp
иlongjmp
.Я думаю, что единственная упомянутая проблема, связанная с С, - это отсутствие стандартных контейнеров. Хотя
Set
в общем случае его можно заменить на отсортированный массив иMap
(по большей части) на массив пар или astruct
(если вы знаете, что ключ, установленный перед рукой,map[key] = value
превращается вs.key = value
), но факт в том, что в стандарте нет контейнера динамического массива библиотека. В C99 вы можете по крайней мере объявить массив переменной длины в стеке (int array[len]
), но вам нужно вычислитьlen
заранее (обычно не сложно) и, конечно, вы не можете вернуть его как любой объект, выделенный стеком. Большинство проектов заканчивают написанием собственного контейнера динамических массивов или использованием открытого источника.В заключительной записке я хотел бы отметить, что я был там. Я был программистом на Java, который перешел на C ++ и чистый C. Я хотел бы посоветовать «прочитай книгу X, чтобы выучить хороший C», но не существует ничего подобного для Java. Способ продвинуться вперед - впитать все тонкости языка и стандартной библиотеки; Google много, много читал, и код много , пока вы не начнете думать в С. Попытка писать вещи в C , как вы бы в Java как разочаровывает , как пытаются написать фразу на иностранном языке со словами непосредственно в переводе с вашей матери язык; и вы, и читатель съежитесь. Хорошая новость заключается в том, что обучение хорошему программированию происходит медленно, а изучение другого языка - быстро. так что если вы пишете достойный код на Java,
источник
setjmp()
/longjmp()
как действительный инструмент: он даже не пытается выполнить какую-либо очистку. Любое распределение будет утечкой, любая удержанная блокировка не будет снята, любой открытый файл не будет закрыт, и любое временное несоответствие данных станет постоянным. ИМХО, эта пара функций - в основном худший взлом, когда-либо изобретенный, с единственным оправданием, что было возможно осуществить это. В конце концов, в Си есть только один действительный способ обработки ошибок: явные коды ошибок.setjmp/longjmp
мне кажется, что рыба из воды в C, и я никогда не использовал их. Я чувствовал себя обязанным включать их только из-за многочисленных учебных пособий / библиотек в Интернете для имитации исключений, поэтому я подумал, что есть люди, которые действительно используют его.Я бы порекомендовал вам быть осторожным в том, стоит ли это вашего времени и денег компании, чтобы тратить ресурсы на «модернизацию» работающего программного обеспечения с низкой сложностью кода и с хорошими показателями. Существует высокая вероятность того, что вы будете вносить новые ошибки самостоятельно, тем более что это система, с которой вы не знакомы.
Если вы все еще хотите пойти по этому пути, я бы предложил следующее:
На этом этапе вы решите, стоит ли это исследовать. Если культура вашей компании не вознаграждает за провал, тогда получите зеленый свет от высшего руководства или менеджера.
Я думаю, что это довольно хорошая дорожная карта и доставит вас туда, куда вам нужно. Не зная специфики этого проекта, вам трудно чем-то помочь. Пожалуйста, не отказывайтесь от моего отказа от ответственности как чрезмерно паникерского. Тонны отличных программистов побили пыль, пытаясь переписать существующий проект на свой любимый язык или используя «современные» инструменты. Это решение должно быть тщательно продумано, и я призываю вас не идти на мошенничество и делать это самостоятельно без поддержки со стороны руководства или помощи ваших коллег.
источник
Если вы предпочитаете язык более высокого уровня, есть некоторые языки, такие как C ++ или Objective-C, которые можно легко смешать с кодом C.
Альтернативно, C и C ++ достаточно совместимы. Возможно, вы сможете просто скомпилировать всю кодовую базу как C ++ с небольшими изменениями - у вас будет случайная переменная с именем «class» или «template», которую нужно переименовать, но на практике это будет все. (sizeof ('a') отличается в C и C ++, но я не думаю, что когда-либо использовал это).
Если вы идете по этому пути, учтите, что следующий сопровождающий может не слишком хорошо владеть C ++. Не увлекайся. Воспользуйтесь преимуществами C ++, но только настолько, чтобы программист C мог легко понять его.
источник
malloc
) считаются плохой практикой в C. Смыслаconst
иinline
также очень отличается от C и C ++, и, конечно , C ++ не понимает__restrict
, Не рассматривайте языки как взаимозаменяемые, даже в подмножестве источников, которые компилируются в обоих.По сути, написание хорошего кода на C - это то же самое, что написание хорошего кода на C ++ или Java: вы хотите класс, используйте a
struct
. Вы хотите наследования, включите базуstruct
в качестве безымянного первого члена. Вы хотите виртуальные функции, добавить указатель на статическиеstruct
указатели функций. И т. Д., И т. Д. Это именно то, что C ++ делает под капотом, единственное отличие состоит в том, что это явно на C. Таким образом, вы можете делать идеально объектно-ориентированное программирование на C, оно просто выглядит немного иначе и более наглядно, чем то, что вы делаете. привыкли к.Дело в том, что хорошее программирование - это парадигмы, а не языковые особенности. Правда, всегда хорошо, если ваши языковые функции обеспечивают хорошую поддержку парадигм, которые вы хотите использовать, но языковые функции не являются обязательными. Как только вы поймете это, вы сможете написать хороший код практически на любом языке (кроме некоторых эзотерических языков, таких как brainfuck или INTERCAL).
Конечно, проблема остается в том, что стандартная библиотека C не содержит ни одного из тех классных контейнерных классов, к которым вы привыкли. К сожалению, это означает, что вам нужно будет либо использовать свой собственный, либо обойти этот недостаток с помощью динамически размещаемых массивов. Но я готов поспорить, что вы скоро обнаружите, что все, что вам действительно нужно, - это динамические массивы (
malloc()
) и связанные списки / деревья, которые реализуются через члены-указатели в ваших классах.источник