#c #c++ #стиль
Нужно ли воспринимать возможность использовать Си в программах на С++, как приятное дополнение или относится только как к обратной совместимости? Есть те, кто считает, что такое использование вредит пониманию, так как другой человек может быть не знаком с некоторыми частями Си или вовсе не знать ничего, кроме С++. Также некоторые считают это плохим стилем, потому что его использование делает код не красивым. Или же с точки зрения убеждений, что код должен содержать конструкции языка, на котором пишешь, а не смешивание new с malloc т.п. Но а как же быстродействие некоторых его частей или использование удобных функций форматирования? Где та грань, которой нужно придерживаться? Я описал только малую часть, так как на большее не хватает знаний. По этому было бы прекрасно, если бы вы ответили не точно следуя этим вопросам, а опираясь на свой опыт и мнение и этим возможно тема раскроется ещё глубже, что в дальнейшем поможет и мне и возможно вам или кому-то другому. UPD: @avp, на материал во второй ссылке буду постепенно поглядывать, но скорей для справки, чем искать повод для переезда на другой язык. Потому как в принципе я согласен со многим, даже при том, что у меня очень мало опыта. Мне кажется, что если начинать с С++, то это скорей будет изучение самого С++, а потом уже возможно через пару лет и программирования, что нельзя сказать про Си, так как он действительно прост в понимании, особенно после С++. И концентрация идет не на разбирание граблей языка или умения работать с stl/boost, а на освоение новых алгоритмов при написании своих костылей. Такие костыли будут в начале плохими и некрасивыми и на них будет уходить много времени в сравнении с использованием готовых решений на C++, но их написание даст понимание как это работает или как это выгодно модифицировать для своих нужд, а не просто использовать STL и даже может разбираться частично как работают его внутренности, но все ровно не быть способным написать что-то подобное на том же языке или другом. Насчет первой ссылки, то встречал подобное и от самого автора(если не фейк) тут и должен сказать на том этапе знакомства с С++, меня это довольно сильно расстроило, так как неважно с какой целью началось изучения языка, но если видишь такое от его создателя, то это не может не задеть. Наверное я бы выбрал Си, если бы вернулся в прошлое, но сейчас буду и дальше продолжать кодить с упором на С++ и поглядывать на С, то есть бежать наверх в низ по ступенькам. Потому что во мне преобладает непостоянность и я просто обязан закончить с этой книгой). Вот такие пироги. P.S. Спасибо за ответы и приношу извинения, если развел здесь оффтоп.
Ответы
Ответ 1
На самом деле, единой точки зрения на это нету. С одной стороны, С — очень мощное подмножество языка, и используя его, можно легко «прострелить себе ногу», то есть, наделать глупых ошибок по незнанию. Например, при помощи макросов можно сделать как много полезного, так и много вредного наподобие #define strcpy(a,b) memmove(a,b,strlen(b)+2), поэтому во многих проектах макросов стараются избегать — тем более, что при помощи гораздо более безопасных темплейтов можно сделать многое из того, что умеют макросы (и кроме того многое другое). Другими частыми источниками ошибок являются смешивание malloc/free и new/delete/delete[] (по стандарту, free(new int) есть undefined behaviour), ручное управление памятью вместо использования смарт-указателей и RAII (источник 90% проблем новичков на ХК), использование массивов (и более продвинутое велосипедостроительство) вместо подходящих стандартных контейнеров std::vector, std::map, std::stack (источник остальных 90% проблем новичков). Особенно сложно даётся новичкам работа со строками (которая, нужно признать, в C организовано не блестяще): немногие осилят правильное чтение строки не известного заранее размера из файла! С другой стороны, многие очень приятные лаконичные конструкции C не имеют прямого «безопасного» C++-варианта, например, обсуждавшийся недавно sscanf. Не стоит забывать, что C — другой язык, с другой идеологией, методологией и эстетикой, поэтому смесь кода на двух языках выглядит ненатурально и является источником ошибок. Например, в C приветствуются лаконичные конструкции: void copy_str(char *p, char *q) { while (*q++ = *p++) ; } — в то время как в рамках C++ этот код слишком плотный, чересчур завязан на конкретные типы, слишком прямо работает с памятью и и слишком надеется на непроверяемые предусловия (априори считается, что q указывает на выделенный кусок памяти размером не менее strlen(p) + 1). Для себя я установил правило: если пишется код на C++, стараться использовать идиоматичные конструкции, чтобы тем, кто читает мой код, было легче понимать его, и чтобы уменьшить вероятность ошибки: если выбран язык C++, а не C, надёжность более важна, чем экономия нескольких тактов процессора. Если же в каком-то месте я вижу необходимость использовать конструкцию из C, я пишу комментарий, обосновывающий эту необходимость. В любом случае, присоединяясь к существующему проекту на C++, узнайте, какие там стандарты на использование конструкций чистого C, и следуйте им. Update (спасибо @alexlz за комментарий!) Заметьте, что в случае ограниченности ресурсов (программирование для контроллеров, например), использование «полноценного» C++ может быть неоправданно затратным. Это усугубляется тем, что компиляторы для таких платформ зачастую выдают плохо оптимизированный код. В таких случаях распространённой практикой является отказ от всего множества языковых фич C++ и ограничение определённым подмножеством. Например, могут быть выброшены лямбды, шаблоны, стандартные контейнеры, исключения, стандартные алгоритмы, введено ручное управление памятью, то есть, итоговый язык будет ближе к чистому C. Но это — не от хорошей жизни (высокоуровневые конструкции позволяют забыть о надоедливых мелочах), и определяется опытным в разработке на данной платформе архитектором проекта.Ответ 2
@strol, программирование само по себе достаточно сложная штука. Язык должен помогать как можно проще и естественней выражать свои мысли. На самом деле С++ язык сложный (а ведь создавался с целью упростить программирование на Си). Поэтому старайтесь писать проще (однако, не проще, чем необходимо) и не слишком переживайте по поводу смешения стилей. Конечно, некоторые вещи, которые на первый взгляд эквивалентны, могут на самом деле оказаться несовместимыми (например, new/delete и malloc/free). Просто о них надо знать, т.е. понимать как реализуются разные конструкции. В самом С++ полно взаимозависимых вещей и добавление чего-то из чистого Си ситуацию не упрощает (но и далеко не всегда усложняет). Примерно на эту тему мне понравилось высказывание Кернигана (кстати, они работали с Страуструпом в Bell labs) в интервью из книги "Пионеры программирования" ...Си занимает прочную позицию среди языков программирования. Он чрезвычайно выразителен, но в то же время не слишком сложен или велик, а кроме того, написанные на нем программы эффективны. ... С этим языком удобно работать, потому что если нужно что-то выразить, он представляет для этого не так много разных способов. Я посмотрю на ваш код и скажу: да, мне понятно, что он делает. Едва ли то же самое можно сказать о таких языках, как Perl или С++. Я посмотрю на ваш код и останусь в недоумении, потому что тут есть много способов написать одно и то же. C++ сложен и огромен, и выразить что-либо можно многими способами. Если мы с вами будем писать на C++, то можем прийти к весьма разным способам описания какой-нибудь большой задачи. В Си такого не бывает. Си сохранился потому, что у него оказалось хорошее соотношение выразительности и эффективности, и для важных приложений он остается лучшим инструментом. .... Бьерн голову себе сломал, пытаясь добиться максимальной совместимости с Си. Одной из причин успеха C++ в сравнении с другими языками была хорошая совместимость на уровне как исходного, так и объектного кода, а это означало отсутствие необходимости полностью перестраивать работу, чтобы использовать C++ в среде Си. .... Одним из крупнейших прегрешений считают чрезмерную близость к Си.... ... Возможно, но чем дальше он отошел бы от Си, тем меньше были бы его шансы на успех. Здесь трудно соблюсти правильную меру, и я думаю, что он очень хорошо справился со своей задачей. (приношу извинения за столь длинную цитату) А некоторые люди вообще высказываются о программировании на С++ довольно кратко, но значительно резче. Здесь весьма обстоятельная критика. Так что, изучайте все получше и делайте выводы сами для себя.Ответ 3
ИМХО, основное достоинство С - возможность написания быстрых программ. А если не быстрых, то совместимых/работающих с быстрыми. С++ - это С с немного более человеческим лицом. Но основная идея - по-прежнему скорость. Допустим, в std::list вы не найдёте метода sort. Хотя, конечно, есть дополна простых, но неэффективных методов типа std::find или insert в vector... Ну что поделаешь, какую-то цену за удобство надо платить. Это всё я к тому, что я считаю возможность смешивания С++ и С стилей одним из главных достоинств языка. Ну лень тебе сегодня - завёл vector. А завтра оказалось, что это всё тормозит - заменил vector на vector , память выделил один раз на все строки, раздал и всё! Я даже память для массивов частенько выделяю через std::string m_memory; ... m_memory.resize(data_size); return m_memory.c_str() Как ни странно, ни разу сильно не огребал из-за подобных шалостей. Гораздо тяжелей было научиться работать со строками без access violation'ов в С, когда только начинал :) Upd: @VladD, ну естественно не на стеке! Имеется в виду член класса, который живёт дольше, чем используется память, которую он держит. Я потому и написал m_: class C { private: std::string m_memory; ... char *GetWorkMemory(int data_zize) { m_memory.resize(data_size); return m_memory.c_str(); } ...
Комментариев нет:
Отправить комментарий