C или c


Содержание

C# или C++ для новичка

всем доброго времени суток! Хочу обратиться с таким вот вопросом:
Я изучал C# где-то месяца 3 самостоятельно (обучался медленно так как был другими вещами еще занят). в итоге конечно научился создавать простые консольные приложения. Моя цель-научиться создавать компьютерные игры, конечно я понимаю что 1 не создам номальной компьютерной игры-это врятли возможно, но я буду стараться и искать напарников.
Часто сталкивался во время обучения: типо C# и идущий с ним ХNA лажа, типо C# лажа и все в таком духе.
вот хочу спросить совета: продолжить учиться на C# или изучать C++ ?
Можно ли на C# создать чото более менее нормальное?
И еще С++ для человека практически незнакомого с программированием можно самому обучаться или опыт програминга будет тут необходим?

C# + XNA мне скажем так не нравится (что бы ни кого не обижать, а то щас начнется)
C# как язык вполне очень даже сильная вещь.
если сравнивать с С/C++, то сложности будут и там и там, не бывает без сложностей :)
хотя сложности имею немного разный характер.
В С/С++ есть очень много ньюансов без знания, которых можно найти очень много шишек на свою опу, но для С++ есть выбор OpenGL vs DirectX
для C# есть можно сказать только XNA, все остальное скажем так самописные либы,
которые не сказать чтоб очень плохи, но они немного отстают от того, что выходит для С++
та же XNA не поддерживает DX10, допустим огловские враперы не поддерживают OpenGL 3.0
можно конечно и самому писать всяческие враперы, но тогда C# становится ни чуть ни легче С++

В данный момент C# больше ориентирован на бизнес приложения, C++ более универсален.

А с++ вполне по силам научиться самостоятельно если опыт програминга очень низкий?

C# не лажа — а очень мощный и перспективный ЯП, причем очень активно развивающийся.

Только вот для игр не подходит ;)
Хотя когда появится работающий silverlight.

Если опыт программиста очень низкий, лучше идти подметать двор, разгружать вагоны.
Вопрос о том что изучать глупый, что бы быть хорошим программистом вы должны знать и то и то.
Вопрос о том можно ли что то сделать на C# — глупый, возьмите и попробуйте. Пока вы сидите и думаете о том,
что лучше с++ или С# за это время можно было бы сделать уже что то, и заработать тот же опыт. Подбросьте монетку в конце концов!

cNoNim
>C# как язык вполне очень даже сильная вещь.
Ути пути, а как же — «С# кал, C++ managed — наше всё»?

  • jenik15
  • Пользователь

C# — будущее и для новичка он не раскрывает, и не показывает «в лоб» всех своих подводных камней! Но, к сожалению, он как ни крути, ориентирован на очень быструю разработку бизнес приложение и максимально повторное использование готового кода, что очень хорошо для сколачивания денег с клиентов в минимальные строки и плохо что он этим и ограничен!
Но будем надеяться, что он обретет могущество с++ и мультиплатформеность java. )

Arturio
> А с++ вполне по силам научиться самостоятельно если опыт програминга очень
> низкий?
Можно. Я же сам научился. Значит и ты сможешь. Опыта программирования у меня небыло вобще. Правда пробовал что-то писать на Visual Basic, но потом понял что этот язык не для меня. С этим языком программирования твои мозги стлеют. Поэтому С++ — лучший выбор. Он универсален. С# разработан для разработок интернет-приложений, и плюс выбора графического API (как сказал cNoNim ) у тебя не будет, только XNA.
Из книжек по С++ посоветую «Как программировать на С++» Х.М. Дейтел, П. Дж. Дейтел, ну и на перспективу книга Бьерна Срауструпа «Язык программирования С++». А выбор графического API это уже другая тема.

Zakus, я как бы не отказываюсь от своих слов :).
С++ managed — наше все. но я не думаю, что в нево лучше лезть с нуля.
а поповоду твоего C# ты бы лучше подсказал мне в соседней теме про маршалинг, раз такой умный и всеми руками за C#.
мне хотелось все сделать по правельному на по хоже без CLI там делать не чего.

C# калечит мозг напрочь. :)

Arturio
> А с++ вполне по силам научиться самостоятельно если опыт програминга очень
> низкий?

А ты думаешь все начинали с огромным опытом? Опыт приходит с практикой.

>С# разработан для разработок интернет-приложений
Куда я попал.

>а поповоду твоего C# ты бы лучше подсказал мне в соседней теме про маршалинг, раз такой умный и всеми руками за C#.
Я буду тратить своё время на помощь ТЕБЕ? :DDD Так ещё и в области не интересной мне?)

>мне хотелось все сделать по правельному на по хоже без CLI там делать не чего.
Это классика жанра — «у меня не получается сделать это, значить язык говно».

Имхо, не имеет значения на каком языке программирования начинать. Главное, понять основные принципы вообще, потом понять ООП в частности, а приложить полученные знания можно в очень короткий срок на любой ЯП, наиболее подходящий для решения конкретной задачи.
Я начинал по довольно стандартной схеме VB6->Delphi7->Builder->MSVC++, сейчас по работе пишу (в той или иной степени) практически на всех известных мне языках программирования кроме ассемблера и фортрана.

Как по мне, так с# идеально подходит для решения бизнес-задач, ибо у него довольно мощная платформа. C++ подходит для решения задач, в которых критична производительность (хотя тут рулит асм, но не впадать же в крайности). CLR С++ на мой взгляд совершенно не удобен по сравнению с C#. Нередко приходится использовать в рамках одного проекта несколько ЯП. Например я пишу двиг на C++, игровая логика работает на Lua, а редактор пишу на C#.

> C# калечит мозг напрочь. :)
Ога, и люди после этого не могут работать без нормальной среды, не могут не проектировать, не могут юзать говнокод, не переписывают тысячи велосипедов а тупо разрабатывают проекты в несколько раз быстрее.
Действительно, как так можно, это же не интересно.

Arturio
Попробуй С++: а) Как проблюешься, приходи на C# + XNA. б) Как войдешь в Нирвану, забудь про C# + XNA.
PS. И научись наконец складывать личное мнение на основе опыта, а не слов от неизвестных тебе людей.

Пусть с бейсика начинает — проверенный путь

C++ или C#? Что учить первым?

17.09.2011, 16:01

Что учить? visual c++ или Borland c++
Какой из них учить.Главное чтобы был легче.

Что проще учить java или c++?
Что проще учить java или c++?.Сам знаю базу с++.Хотелось бы узнать про язык java.Вот при изучении.

Что лучше учить сначала C или C++? Выбор литературы.
Что лучше учить сначала C или C++? Или в перечисленных ниже книгах материал по C уже есть? Также.

Имеет ли смысл продолжать учить с++ или попробовать перейти в с# или java?
Надеюсь данный вопрос не нарушает правила этого раздела. Учу кресты уже месяца полтора-два. Это.

17.09.2011, 16:10 2

C++ Beginner, C++ будет для вас сложнее, если вы до него привыкните к другому языку.

При выборе учитывайте, что C# — это только Microsoft, то есть вы будете привязаны в VS и Windows. C/C++ используется практически везде. На них написано очень много ПО для винды и юниксов (в том числе мака). К тому же PHP использует много функций, похожих на функции стандартной библиотеки C.

17.09.2011, 16:15 3 17.09.2011, 16:17 4
17.09.2011, 16:17
17.09.2011, 16:19 5

Решение

C# синтаксически богаче плюсов, поэтому как язык не может быть легче по определению (магию шаблонов и макросов в расчет не берем). Писать на нем быстрее и приятней, но не легче.

C++ Beginner, дело не в языке, а в голове и том как Вы думаете, поэтому какой язык Вы выберете не важно.

17.09.2011, 16:51 [ТС] 6

Скорее по C++ слишком много хреновых книг, если с выбором литературы не ошибится, то проблем не должно быть.

C# синтаксически богаче плюсов, поэтому как язык не может быть легче по определению (магию шаблонов и макросов в расчет не берем). Писать на нем быстрее и приятней, но не легче.


C++ Beginner, дело не в языке, а в голове и том как Вы думаете, поэтому какой язык Вы выберете не важно.

17.09.2011, 16:52 7
17.09.2011, 17:03 8
17.09.2011, 17:41 9
17.09.2011, 18:16 10
17.09.2011, 18:30 11

Ну, лично я начал с C#. Впрочем, обучали нас на курсах «профессионалы». Так что выбор очевиден. В принципе, да — C# очень прост в обучении. Но важно знать, что он создавался с оглядкой на C++. Вообще, лично мне он ОЧЕНЬ напоминает смесь C++ и Java. Например, в программе есть как минимум один класс — без него не запустится. Но в то же время семантика (мля, как-то сложно, не уверен то ли вообще говорю) языка чем-то схожа с C++. Ну, то есть очень многие понятия были переняты из C++.

Впрочем, если есть возможность, то лучше сразу изучать Java. Принципиальные отличия, конечно, есть, но возможности у этого языка гораздо выше, куда проще в обучении, да и в нашем мире более востребован и применений имеет более широкое. Самый главный минус — низкая производительность, но это, так сказать, константа. То есть программа, грубо говоря, будет работать в два-три-десять раз медленнее аналогичной, но написанной на C++, но зато это практически не зависит от объёма задачи (входных данных). Кстати, это относится и к C#. Производительностью он не блещет.

Впрочем, изучайте то, что хотите. C++ я после C# изучил и даже более досконально. И никаких проблем — спокойно изучаю самостоятельно и C++ (продолжаю) и платформу .NET [стараюсь — никто не помогает =( ]. C++ проще начинать изучать. Синтаксис его, всё же проще и нет за***ва с классами. Поэтому первые, тривиальные программы очень просты, понятны и прозрачны. По «встроенным» возможностям, C++, конечно, уступает его родственнику, но это с лихвой компенсируется полнотой Тьюринга и более быстрым компилятором, а также более эффективной работой.

C или c?

На чем основано ваше высказывание? На пример мы при тестах в инсте узнали, что среди аналогичныч программ на C++ и C# работающих через ADO с SQL базой на C# работают быстрей.

Ну а на счет скорости запуска и занимаемой оперативной памяти C++ конечно впереди.

На чем основано ваше высказывание?

Ну а на счет скорости запуска и занимаемой оперативной памяти C++ конечно впереди.

ну,во первых ADO это адо,попробуй заклиентиться через сеть,увидишь странные результаты,скорость от теста к тесту будет меняться то в пользу .NET то в пользу С++
на С++ можно написать механизм работы с АДО обгоняющий шарп,но нахрена если разницы не заметишь?

а вообще кей правильно сказал:
«Actually I made up the term \»object-oriented\», and I can tell you I did not have C++ in mind.»
P.S.
повторюсь-выбирай что душе ближе,хоть питон :)

Сообщение отредактировал tz-lom — 17.01.09, 18:15

Ага, все уже пистолеты наточили? Ну тогда и я выскажусь.
Независимо от всех споров и высказывания мнений, каждый все же выбирает тот язык, на котором ему писать удобно или необходимо.
Новичкам, понятное дело, нравится C# ввиду его легкости, но нельзя забывать, что на кпк фреймворк при запуске «отъедает» изрядное количество ресурсов. Быстродействие кода C# не намного меньше чем у C++, когда необходимые сборки уже скомпилированы (например, код вызывается второй и последующий разы после старта приложения и до его завершения). Но при старте, разумеется, .NET программы сильно проигрывают нативным приложениям.
Еще про C# хотелось бы сказать, что при его использовании для реализации сложных вещей этот язык не намного проще C++ или С (закоронелые дотнетчики, попробуйте сделать клиент-сервер с ремоутингом, и вы поймете, о чем я).

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

Вывод — если надо написать какую нибудь программку, чтоб похвастаться перед знакомыми, хватайте C# или VB.NET — и в путь.
Если хотите написать потом и что-то посложнее — лучше сразу начинать с C++.
Однако, если мне нужно быстро написать огромное приложение без особых требований к железу но зато с огромной кучей бизнес-логики, то выбор обычно падает на дотнет, к моему большому стыду.
Воооттт. :)

это говорит лишь о том, что «аналогичную программу» на си писал кто-то очень криворукий.

Помнится аналогично скептически относились и к Delphi, типо она очень не эффективный код компилит, пока пара людей не провела нормальные тесты с дизассемблированием аналогичных программ на Delphi и на C++, которые и показали что разницы критичной в общем то и нет и все это лишь ИМХО заядлых программеров.

Я прекрасно понимаю людей которые всю жизнь программили на Си, а тут вдруг появился СиШарп, да еще и ненативный какой то :happy: Людям свойственно отрицать то, что им не привычно. А вы вот для начала попробуйте сами проведите элементарные тесты и проверьте результаты (именно работы приложений). И кстати, скорость запуска .NET приложений заметна только на КПК, на ББ вприципе уже и разницы то не заметно, так что с приходом гигагерцовых мобильных процов, интегрированных видеоподсистем и более быстрой оперативной памяти на КПК, я думаю, что грань между нативом и не нативом сотрется для пользователя (сам кстати тоже не люблю .NET).

Сообщение отредактировал shep — 17.01.09, 22:22

shep,
ну,во первых я как пользователь традиционно старых компов (3,5 года назад у меня в ЛИЧНОМ пользовании был только 386 под который я писал программы,далее pentium 166 и небывало мощный целерон аж 2 гигагерца с целыми 512МБ на борту и встроенной видеокартой в подарок!) просто терпеть не могу ненативный код,и если на твоей машине запуск дотнет программ не заметен,то я им мог «наслаждаться» и по 40 секунд и более.
це раз
на Delphi я пишу ещё с. правильно,386го :),на первой делфе,и никогда не имел претензий к выдаваемому бинарнику и скорости его работы (не тормозило)
с приходом терагерцовых процов и прочей хрени правило «пиши хороший быстрый код» никто не отменил,ибо все эти терагерцы и пикобайты с радостью сожрёт индусский код от мелкософт (дотнет в том числе)

про всю жизнь на Си это опять таки мимо,я вообще ненавижу С++,хоть и пишу на нём :lol:
да,вот такая вот загадка,ибо приходится,когда нибудь (когда доделаю всё что надо доделать) я радостно пополююсь в сторону С++ и буду его обсирать как сейчас дотнет :rofl:
а пока я просто хочу призвать людей писать так как это ближе к системе,понимать КАК выполняется их код,что такое компьютер и ОС внутри,а не писать индоподелки которые работают чёрт его знает как
в конце концов хороший программист на .NET это всего лишь хороший программист на .NET,не более а Сишник сможет же при желании изучить синтаксис да хоть ассемблера и писать на нём не менее хорошие программы,ибо понимание Си приводит к пониманию как работают эти железки >-)

shep,
ну,во первых я как пользователь традиционно старых компов (3,5 года назад у меня в ЛИЧНОМ пользовании был только 386 под который я писал программы,далее pentium 166 и небывало мощный целерон аж 2 гигагерца с целыми 512МБ на борту и встроенной видеокартой в подарок!) просто терпеть не могу ненативный код,и если на твоей машине запуск дотнет программ не заметен,то я им мог «наслаждаться» и по 40 секунд и более.
це раз
на Delphi я пишу ещё с. правильно,386го :),на первой делфе,и никогда не имел претензий к выдаваемому бинарнику и скорости его работы (не тормозило)
с приходом терагерцовых процов и прочей хрени правило «пиши хороший быстрый код» никто не отменил,ибо все эти терагерцы и пикобайты с радостью сожрёт индусский код от мелкософт (дотнет в том числе)

про всю жизнь на Си это опять таки мимо,я вообще ненавижу С++,хоть и пишу на нём :lol:
да,вот такая вот загадка,ибо приходится,когда нибудь (когда доделаю всё что надо доделать) я радостно пополююсь в сторону С++ и буду его обсирать как сейчас дотнет :rofl:
а пока я просто хочу призвать людей писать так как это ближе к системе,понимать КАК выполняется их код,что такое компьютер и ОС внутри,а не писать индоподелки которые работают чёрт его знает как
в конце концов хороший программист на .NET это всего лишь хороший программист на .NET,не более а Сишник сможет же при желании изучить синтаксис да хоть ассемблера и писать на нём не менее хорошие программы,ибо понимание Си приводит к пониманию как работают эти железки >-)

Не спорю ни с 1 словом. Программиста, который знает только ненативные языки программирования программистом не считаю (он скорее оператор ЭВМ :P )

C или C++ что выбрать

День добрый! Я начинающий программист, очень хочется писать под Linux. Что же мне выбрать C или С++? Порекомендуете! Заранее спасибо!

Re: C или C++ что выбрать

Мне лично, больше нравится С99.

Re: C или C++ что выбрать

С Си будет жить проще. Когда станет не хватать, учи сразу схему/лисп

Re: C или C++ что выбрать

Re: C или C++ что выбрать

А в каком направлении хочется писать?

Re: C или C++ что выбрать

Re: C или C++ что выбрать

Re: C или C++ что выбрать

> А в каком направлении хочется писать?

BioReactor real-time control management.

Re: C или C++ что выбрать

в направлении сетевых приложений, в частности в области Ldap.


Re: C или C++ что выбрать

Re: C или C++ что выбрать

>А в каком направлении хочется писать?

Настенная живопись, то бишь расписание стен остатками живых программистов.

Re: C или C++ что выбрать

Сначала лучше выучить C

Re: C или C++ что выбрать

Да и лучше не учить, а решать какие-нибудь задачи, используя Си как инструмент. Практика в первую очередь.

Re: C или C++ что выбрать

Если ничего до сих пор серьзного не написал, то лучше всего начать с C. Потом к чему-нибудь более специализированному и удобному в своей области.

Существует обоснованное мнение, что если на чём то пишешь, то нужно знать как оно работает. т.е. используешь Java — разберись с устройством VM и GC. Используешь Python — напиши пару интерпретаторов. Используешь C — учи asm. ;)

Re: C или C++ что выбрать

Тему сперва в talks, потом в топку :)))

А вообще, конечно pure C :) или С & glib

Re: C или C++ что выбрать

Недавно в Москву приезжал дядька из МС, говорил, что они давно уже экспериментируют с Хаскелем. Уверял, что ФП и в частности Хаскель — это очень круто, потому что можно автоматически распараллеливать код, а это сейчас очень важно в свете многоядерных процессоров.

Re: C или C++ что выбрать

А на μC++ они не смотрели?

Re: C или C++ что выбрать

Кстати, есть еще C#! :)

Re: C или C++ что выбрать

не знаю, может и смотрели, но упомянул он только о Хаскеле

Re: C или C++ что выбрать

>Недавно в Москву приезжал дядька из МС, говорил, что они давно уже экспериментируют с Хаскелем.

вас это удивляет? ghc разрабатывается в microsoft research’е

>Уверял, что ФП и в частности Хаскель — это очень круто, потому что можно автоматически распараллеливать код, а это сейчас очень важно в свете многоядерных процессоров.

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

Re: C или C++ что выбрать

>то что можно — это все понятно(функции «чистые»), но на практике не выгодно автоматически распараллеливать

и что сие должно означать ?

>хотя паралелизовать при помощи Control.Parallel очень легко и понятно, хотя явный хак

в каком месте это хак, да ещё и явный ?

>ну еще не стоит забывать про ленивость, она сильно производительность снижает

совершенно верно. только не всегда, не сильно, не снижает. и не ленивость

Re: C или C++ что выбрать

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

Re: C или C++ что выбрать

> ну еще не стоит забывать про ленивость, она сильно производительность снижает

В теории она вовсе не обязана этого делать. И умные компиляторы об этом знают (см. Clean).

C или c?

Доброго всем времени суток, прошу помощи в разрешении небольшой дилеммы :)

Являюсь студентом IT-факультета института. В институте учат С++. Сам я два года изучал C# (не слишком глубоко). Препод сказал что можно писать с тем условием, что я самостоятельно буду изучать C#.

Вопрос: стоит ли переходить на самостоятельное глубокое изучение C# или всё таки следовать курсу институтской программы и начать изучать С++?

Всё вышенаписанное является моим мнением и может не совпадать с Вашим. Грамматические ошибки так же являются авторским стилем изложения ^_^

Все ответы

Да на начальном уровне я оба языка знаю. C# действительно кажется легче, пока не начинаются интерфейсы, делегирование и прочие страшные слова >. . Всё вышенаписанное является моим мнением и может не совпадать с Вашим. Грамматические ошибки так же являются авторским стилем изложения ^_^


C# объективно легче и стройнее чем C++. Он намного моложе и создавался с учетом опыта предыдущих языков (Java, Pascal, C). Он гораздо более гармоничный чем C++. Ну а C++ создавался «на коленке» в нем перемешаны куча всевозможных технологий, он имеет несбалансированный синтаксис, кучу разносортных библиотек и методик.

Сейчас С++ отошел на второй план и занял свою нишу high-performance приложений (игры, движки БД и т.п.). C# же позиционируется как язык для корпоративных десктоп-приложений. Он не обеспечивает максимальный перформанс, зато разработка в разы быстрее чем на C++.

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

>Вопрос: стоит ли переходить на самостоятельное глубокое изучение C# или всё таки следовать курсу институтской программы и начать изучать С++?

Эх, а вообще, все это такие мелочи. Что есть язык? В языке десяток операторов и пару базовых конструкций, которые учатся за два дня.

>Да на начальном уровне я оба языка знаю. C# действительно кажется легче, пока не начинаются интерфейсы, делегирование и прочие страшные слова >.

Записки программиста

Почему не лишено смысла писать код на C, а не на C++

11 февраля 2020

Сегодня мы поговорим на тему «C против C++». Некоторые читатели данного блога уже знакомы с моей точкой зрения по этому поводу. Когда встает вопрос с формулировкой вроде «похоже, мы решаем задачу, где очень важна скорость выполнения кода, и нужно выбрать между языками C и C++», в последнее время я склонен рекомендовать C. Многие программисты при этом недоумевают, мол «как же так, ведь С++ новее и имеет больше фичей, и вообще C входит в него как подмножество». Поэтому я хотел бы подробно объяснить свою точку зрения один раз в данном посте, так как каждый раз объяснять ее заново занимает ощутимое количество времени.

Хотелось бы начать с небольшого дисклеймера. Всегда найдутся люди, которые пишут на C++ последние лет 20, и потому (1) они искренне считают язык простым и понятным, (2) им не хочется учить что-то новое, ведь их и здесь неплохо кормят. Это, собственно, и есть так называемый C++ головного мозга. Далее я предполагаю, что читатель не страдает от этого недуга и не утратил трезвость восприятия и открытость мышления по каким-либо иным причинам. Также стоит отметить, что в вопросах «какой язык лучше» нет правых и неправых. Одни и те же объективные преимущества и недостатки воспринимаются разными людьми с разными весовыми коэффициентами, поэтому на выходе получаются разные значения функции fitness. В этой заметке мне хотелось бы пояснить причины, по которым у меня весовые коэффициенты выставлены так, как они выставлены, а не доказать, что у кого-то они выставленные неверно.

Сразу отмечу, что я не считаю, что C++ умер, что это ужасный и совершенно ни на что не годный язык или что-то в этом роде. Трудно ругать язык, на котором написаны Chromium, Skype, Sublime Text и множество других программ, которые я использую каждый день. Не говоря уже о великом множестве хороших библиотек на С++. Тут мне сразу вспоминаются, например, Assimp и wxWidgets. Более того, вы можете помнить, что в заметке Критика языка Rust и почему C/C++ никогда не умрет я отстаивал C++ и говорил, что в обозримом будущем он никуда не денется. Нельзя исключать и культурный фактор. Так игры AAA класса принято писать на C++, потому что в индустрии уже много лет все так делают. Если вы работаете в этой индустрии, то особого выбора у вас может и не быть.

Несмотря на все это, я считаю, что в третьем тысячелетии лучше не писать нового кода на C++, если, конечно, (!) у вас есть такая возможность. И далее я постараюсь более подробно объяснить эту точку зрения.

Примечание: Специально для читателей, считающих, что на C давно никто не пишет, спешу сообщить, что это не так. В первую очередь на C, конечно же, ведется разработка всех современных операционных систем, драйверов, и подобных вещей, например, систем виртуализации. Многие десктоп приложения все так же пишутся на C, например, Claws Mail, Liferea, XChat, Transmission, Gimp, Pidgin, Tox, а также оконные менеджеры и десктоп окружения — Xfce, Lxde, Awesome, i3, и другие. Серверные приложения также часто разрабатываются на C. Тут вспоминается HAProxy, lighttpd, Nginx, Nagios, Memcached, Redis и PostgreSQL. Еще можно вспомнить, например, виртуальную машину языка Erlang и интерпретатор языка Python. Все эти приложения объединяет то, что они должны использовать доступные им ресурсы максимально эффективно — десктоп приложения должны хорошо работать на бюджетных компьютерах, даже таких, как Raspberry Pi, серверные приложения должны обрабатывать как можно больше запросов в секунду, и так далее.

Итак, основная идея, пожалуй, состоит в следующем. Если вы решаете задачу, где действительно очень важна скорость (определение см далее), вы все равно не сможете использовать C++. Вы, вероятно, сможете писать на так называемом «C с классами» или «C с шаблонами». Эти диалекты языка C, бесспорно, имеют право на жизнь. И если вы называете «языком C++» эти диалекты, то я, пожалуй, с вами даже соглашусь — для задачи надо брать «язык C++», срочно! Только нужно при этом быть очень уверенным, что через год вы не выйдите за рамки «C с шаблонами». Эта действительно большая проблема на практике и она более детально описана далее.

Однако большинство людей под С++ понимают так называемый «современный C++», со счетчиками ссылок, классами, исключениями, шаблонами, лямбдами, STL, Boost, и так далее. То есть, тот C++, на котором вы пишите, почти как на Java, в котором никогда не встречаются обычные указатели, и вот это все. Если вам очень важна скорость, то писать на таком C++ вы не сможете. Если же он вам подходит, то лучше взять Java, Go или любой другой высокоуровневый язык по вкусу. В них все те же возможности реализованы намного лучше. А узкие места при необходимости, которой, впрочем, может и не возникнуть, вы всегда сможете переписать на C.

Позвольте пояснить, что я имею ввиду под задачами, где очень важна скорость. Вы едете на машине. Вдруг в нескольких метрах впереди выбегает человек. На принятие решения водителю в среднем требуется около одной секунды. Нога мелено перемещается с педали газа на педаль тормоза. Затем медленно вдавливает тормоз в пол. Расстояние между автомобилем и человеком в это время сокращается. Наконец, сигнал от педали тормоза летит в бортовой компьютер автомобиля. И вот тут ни в коем случае программа не может сказать «о, счетчик ссылок обнулился, пойду-ка я собирать мусор по всему дереву» или даже «секундочку, я только схожу в vtable… как, ее нет в L1? ой…». Программа должна обработать сигнал как можно быстрее, тут же ударив по тормозным дискам. Ни о каких смартпоинтерах и прочих видах автоматического управления памятью, ровно как и о развесистых иерархиях классов, в таких задачах и речи быть не может.

Из менее драматичных примеров можно привести любую систему, где не работает правило «90% времени выполняется 10% кода, эти 10% и будем оптимизировать». Если код, который выполняется всего лишь 10% времени, ускорить на 1/20, суммарная производительность вырастит на жалкие 0.5%. Но в масштабах компании вроде Google или широко используемого приложения вроде PostgreSQL или Nginx эти 0.5% ускорения могут означать миллионы долларов экономии. То есть, несколько месяцев работы небольшой группы программистов в этом направлении окупаются с лихвой. А раз так, почему бы, например, не отказаться от STL совсем и сразу не использовать алгоритмы и структуры данных, заточенные под конкретный случай (примеры есть далее по тексту)?

Я могу привести еще много примеров такого рода. Но идея, надеюсь, ясна. Если решаемая вами задача такова, что написать 90% кода на высокоуровневом языке и 10% на C никак нельзя, то ни на каком «C++, который почти как Java, только компилируемый в машинный код» вы писать не сможете. Если же в вашей задаче можно не париться по поводу 0.5% производительности, то скорость вам нужна не так сильно, как вы думали.

Серьезно, возьмите лучше Go, Java, или любой другой язык по вкусу. Сборка мусора там сделана намного лучше (напомню, что счетчики ссылок плохо работают для большого количества быстро умирающих объектов), прочее управление ресурсами, управление зависимостями, инструменты разработки (IDE и прочие), генерики, лямбды, неймспейсы, исключения, автоматический вывод типов, классы и интерфейсы там сделаны намного лучше. В качестве бонуса вы получите существенно большую скорость разработки, куда более читаемые сообщения об ошибках, куда более лучшую кроссплатформенность, простую отладку, высокую скорость компиляции и так далее, за что там обычно вполне заслуженно ругают С++. Да и найти достойных программистов на этом другом языке станет на порядок проще.

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

  • Согласно книге The Design and Evolution of C++, язык C++ был создан Страустропом, как «C для крупных проектов». Однако практика показывает, что на C вполне успешно разрабатываются очень даже крупные проекты. А от многих возможностей языка C++ отказываются даже в проектах, которые не являются такими уж крупными. Потому что возможности эти зачастую не упрощают разработку, а лишь усложняют ее. То есть, C++ не только плохо решает изначальную проблему, но и усложняет ее решение, да и проблемы то, оказывается, не было вовсе.
  • Лямбды и прочие ништяки не всегда получается использовать на работе, так как о C++11 там только мечтают. К сожалению, многие реальные проекты на C++ в наше время — это страшный легаси с C++98, самописным STL, форкнутым Boost, Visual Studio 6 и CVS. Может быть, я тут немного и преувеличиваю, но идея, надеюсь, ясна.
  • Сложность кода. Если вы видели код на C++, реальный, а не из учебника, то знаете, что он часто он оказывается действительно очень непрост для восприятия. Из недавних примеров мне вспоминается GLM. Так выглядит его исходный код (только один из файлов, их там еще очень много), а так выглядит код на Си, который делает вообще все, что мне было нужно на самом деле. Бесспорно, после 20 лет программирования на C++, код GLM любому покажется простым, понятным и элегантным. Но у меня нет 20 лет, чтобы постигать это темное искусство, мне нужно решать задачи сегодня. Проблема еще в том, что на C++ так пишут довольно часто и, например, чтобы понять, как работает реализация алгоритма сжатия, тебе еще нужно очень хорошо знать, как в C++ работают стримы. А как ты без стримов будешь использовать свой алгоритм сжатия повторно? По теме сложности кода на C++ еще можно привести пример c chrono из статьи Продолжаем изучение OpenGL: простой вывод текста.
  • Пример со стримами хорошо иллюстрирует, что C++ — словно вирус. Все начинается с использования какой-то одной маленькой его возможности, и через какое-то время весь проект кишит лямбдами, шаблонами и вот этим всем, и в этом уже никто не может нормально разобраться. Судите сами. Допустим, вы решили использовать классы. Но вот проблема — все private поля объявляются в .hpp файле и при изменении приводят к перекомпиляции половины проекта (в C такой проблемы с инкапсуляцией нет совсем). И вот в дополнение к простому и понятному классу вам уже приходится использовать не такую уж понятную и простую в реализации идиому pImpl (или фабричный метод, что еще менее производительно). А затем еще правильно перегрузить оператор присваивания, реализовать конструктор перемещения, и чтобы при этом все это добро правильно работало с STL… Мы всего лишь хотели классов, помните? Аналогично вы не можете использовать исключения, не обернув все в умные указатели, которые, напомню, являются классами и используют шаблоны, а чтобы кода было поменьше, придется еще использовать и auto. Аналогично вы не можете использовать классы и конструкторы, не используя исключения, так как нормально вернуть ошибку из конструктора можно только бросив исключение. Таким образом, не платить за то, что не используешь, вот как-то не получается — приходится использовать сразу все.
  • ООП. Кажется, сегодня уже вся индустрия осознала, что объединение кода и данных — идея так себе, не говоря уже про повсеместное использование наследования. В теории это, конечно, здорово, когда есть класс животное и от него наследуется кошка и лошадь. Но на практике реальная необходимость (ООП головного мозга — тоже тяжелый недуг!) строить такие иерархии возникает очень редко, и если возникает, то дело обычно ограничивается одним интерфейсом и многими классами, реализующими этот интерфейс. Последнее, если что, очень просто делается на С. И возникает вопрос, а какой вообще смысл использовать язык, одна из главных фишек которого — возможность легко писать код так, как это делать не надо?
  • STL часто преподносится так, словно в мире С нет библиотек с готовыми алгоритмами и контейнерами, что, разумеется, не так. При этом STL предлагает только одну из многих возможных реализаций (даже для простого vector их можно придумать десятки) конкретного алгоритма или контейнера. Почему кто-то за меня решил, что замедление скорости компиляции и разбухание секции кода лучше, чем, например, хранение всего по ссылке и, соответственно, быстрая компиляция и разбухание кучи? Или, например, хранение всего по значению, но с небольшим замедлением скорости выполнения кода? Следует также отметить, что контейнер, написанный с нуля и заточенный под данный конкретный случай, позволит вам повысить производительность на те самые «жалкие 0.5%», которые так важны в задачах, на решение которых претендует С++. Например, если вы знаете что-то о природе данных, которые хранятся в контейнере, то можете опустить некоторые проверки. Или, возможно, вам известно, что данные удаляются из хэш-таблицы только в порядке обратном тому, в котором они были добавлены — это тоже можно использовать.
  • Из-за повсеместного использования шаблонов скорость компиляции кода на С++ просто ни на что не годится. Не говоря уже о том, что при компиляции крупных проектов нередко может потребоваться, скажем, гигов 10 оперативной памяти. Для сравнения, язык C позволяет мне компилировать по много раз на дню миллионы строк кода, используя только Raspberry Pi. Ну и если я вдруг решу, что в моем проекте имеет смысл использовать кодогенерацию, ничто не мешает ее использовать. Притом, с нормальным кэшированием результата. Понятное дело, так как шаблоны объявляются в .hpp файлах, их изменение приводит к перекомпиляции половины проекта. См также Десять причин избегать метапрограммирования.
  • Как уже отмечалось, если вы берете исключения, то будьте готовы использовать для всего RAII и смартпоинтеры, а следовательно и тормозить, когда счетчики ссылок обнуляются. Иначе одно неудачно брошенное исключение приведет к тому, что все ваши ресурсы утекут. Следует также отметить, что исключения добавляют коду неявного поведения, и далеко не всем программистам это нравится. Как по мне, в задачах, где используется С и/или С++, лучше использовать старые-добрые коды возврата. Пожалуй, придется написать чуть больше кода и завести привычку всегда проверять возвращаемые значения. Зато вы будете точно знать, что и как именно делает ваш код, безо всякой магии. Не удивительно, что в том же Google в коде на С++ исключения не используются, и что в новых языках, таких, как Go и Rust, исключений не предусмотрено.
  • По своему опыту могу сказать, что отлаживать код C++ — мягко говоря, удовольствие ниже среднего. Продраться через тонны смартпоинтеров и виртуальных методов, или, например, посмотреть, что же происходит внутри STL, в gdb подчас сложно настолько, что проще прибегнуть к обычному отладочному выводу. В языке C все просто и понятно. Даже весьма непростые баги можно легко поймать за пару минут. Я вам даже больше скажу, код на C можно довольно комфортно отлаживать вообще без отладочных символов. Когда-то очень давно я так и делал, просто брал OllyDbg и дебажил. Попробуйте, это правда не сложно.
  • Код на C прекрасно пишется без каких-либо тяжеловесных >для C++ существуют. CLion, например, довольно неплох. Но не все программисты согласны платить за него деньги и попрощаться с 2 Гб оперативной памяти. К тому же, CLion не все и не всегда подсвечивает правильно, и если открыть в нем сразу два проекта, то даже довольно мощный компьютер начнет тормозить. Есть и другие IDE, но у них свои проблемы, например, привязка к Windows или отсутствие важных возможностей, таких, как вывод типов.
  • Нельзя упускать из виду и кадровый вопрос. Язык С сравнительно прост. По крайней мере, его реально уместить целиком в голову среднего программиста. Стандарт С11 [PDF] занимает 700 страниц со всеми приложениями и предметным указателем, а полноценный компилятор C умещается в 15-20 тысяч строк кода. Многие (не все, но многие) студенты уже на первом курсе в состоянии писать вполне сносный боевой код на C. Язык C++ в десятки раз сложнее C. Не удивительно, что его толком не знает никто. В лучшем случае, есть люди, которые знают небольшую его часть. Что намного хуже, с выходом каждого нового стандарта С++ становится еще более сложным и запутанным. Туда тянут еще какие-то концепты, корутины и прочие модные игрушки, как будто без них язык не был уже достаточно распухшим. Но хуже всего то, что правила языка часто далеко не очевидны (например) и имеют кучу исключений. Чтобы писать что-то серьезное на языке, про который неизвестно точно, как работают его компоненты и как они друг с другом взаимодействуют, нужно быть либо очень смелым, либо очень глупым.
  • Ну и до кучи. (1) Далеко не везде есть компилятор C++, особенно если это какой-нибудь C++11/14/17. Так что, если вы хотите настоящей переносимости кода, пишите на С. Язык C есть реально везде. (2) Раз взаимодействие между разными языками программирования или, например, вызов процедур из динамических библиотек, все равно происходит через C API, может лучше просто писать на C? (3) Я уже говорил про совершенно нечитаемые сообщения об ошибках в C++? Попробуйте использовать тот же chrono, например. (4) Александреску в итоге ушел заниматься языком D. Мейерс тоже завязал с C++. Mozilla и Google сделали свои языки для замены C++. Наводит на размышления, согласны?

Не удивительно, что и сегодня даже для новых проектов многие программисты (Линус Торвальдс, пожалуй, является самым известным примером) выбирают язык C, а не C++. Стремление писать код на C — это стремление к максимально простому и понятному коду, стремление использовать ресурсы как можно более эффективным образом, и не в последнюю очередь это стремление к красоте. Технологии появляются и исчезают. Подходы, которые еще вчера считались общепринятой практикой, сегодня уже причисляют к антипаттернам. И только C прекрасен и вечен. На чем еще писать, если с 1972 года люди так и не придумали ничего лучше?

C или c?

Почитав Б.Страуструпа, Г.Буча и вообще книги об объектно-ориентированном программировании, некоторые приверженцы C делают вывод о том, что C++ — это нечто запредельно сложное и гиганский шаг вперед. Это заблуждение. На самом деле C++ — это тот же C, но с некоторыми удобными упрощениями. Если вы — хороший С-программист и воспринимаете C++ как нечто на порядок более крутое, то это — диагноз. Который называется «перечитал заумных книжек». Это излечимо J

Часто можно слышать споры на тему: писать на C или на C++? При этом существует расхожее мнение о том, что есть два стиля написания программ: стиль С и стиль C++. Они противопоставляются друг другу. C++ ассоциируется с ООП (объектно-ориентированноым программированием), а чистый C — с ПОП (процедурно-ориентированным программированием). ООП и ПОП также противопоставляются.

На самом деле, все, что есть нового в C++ — уже было в C и вы этим пользовались (если действительно много программировали на C). Только в C++ это записывается чуть по-другому. Однажды у меня вышел спор с одним из приверженцев C на эту тему, в результате чего был написан список из 10 различий между двумя языками.

Различие 1. Объекты

В C++ появились классы и объекты. Технически класс C++ — это тип структуры в C, а объект — переменная такого типа. Разница только в том, что в C++ есть еще модификаторы доступа и полями могут быть не только данные, но и функции (функции-методы).

Функция-метод — это обычная функция C, у которой первый параметр — это указатель на структуру, данные которой она обрабатывает: this. Если сравнить, как выглядят функции-методы в C++ и функции с параметром-указателем на структуру в C, то мы обнаружим, что всего лишь изменилась форма записи. В C++ получается короче, так как this и имя типа во многих случаях писать не обязательно (подразумевается по умолчанию).

Модификаторы доступа — это слова public, private и protected. В C вместо них была внимательность программиста: public — значит с этими полями делаю, что хочу; private — значит к этим полям обращаюсь только с помощью методов этой структуры; protected — то же, что public, но еще можно обращаться из методов унаследованных структур (см. следующий пункт).

Различие 2. Наследование

То, что в C++ — наследование, в C — это просто структура в структуре. При программировании в стиле C++ применяются такие красивые и звучные слова, как «класс Circle порожден от класса Point» или «класс Point наследуется от класса Circle и является производным от него». На практике все это словоблудие заключается в том, что структура Point — это первое поле структуры Circle.

При этом реальных усовершенствований два. Первое — поля Point считаются так же и полями Circle, в результате доступ к ним записывается короче, чем в C. Второе — в обоих структурах можно иметь функции-методы, у которых имена совпадают с точностью до имени структуры. Например, Point::paint и Circle::paint . Следствие — не надо изобретать имена вроде Point_paint и Circle_paint, как это было в C, а префиксы Point:: и Circle:: в большинстве случаев можно опускать.

Различие 3. new и delete

В C++ появились две новые операции: new и delete. В первую очередь это — сокращения для распространенных вызовов функций malloc и free:

При вызове new автоматически вызывается конструктор, а при вызове delete — деструктор (см. следующий пункт). Так что нововведение можно описать формулой: new = malloc + конструктор, delete = free + деструктор.

Различие 4. Конструкторы и деструкторы

Когда программируешь в стиле C, после того, как завел новую переменную типа структуры, часто надо ее инициализировать и об этом легко забыть. А перед тем как такая структура закончит свое существование, надо ее почистить, если там внутри есть ссылки на какие-то ресурсы. Опять-таки легко забыть.

В C++ появились функции, которые вызываются автоматически после создания переменной структуры (конструкторы) и перед ее уничтожением (деструкторы). Во всех остальных отношениях это — обычные функции, на которые наложен ряд ограничений. Некоторые из этих ограничений ничем не оправданы и мешают: например, конструктор нельзя вызвать напрямую (дестркутор, к счастью, можно). Нельзя вернуть из конструктора или деструктора значение. Что особенно неприятно для конструктора. А деструктору нельзя задать параметры.

Различие 5. Виртуальные функции

Из всех усовершенствований это вызывает наибольшую «щенячью радость». Как обычно, придуманы и звучно-научно-рекламные названия: «полиморфизм», «виртуальный», «абстрактный». Если отбросить разницу в терминологии, то что получим в сухом остатке? А получим мы очередное сокращение записи. И очень большое сокращение.

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

Обычное решение — построить таблицу соответствия «вариант структуры — фукция». Затем берется очередной примитив, определяется его тип, и по таблице вызывается нужная функция. В C этот метод применять довольно нудно из-за того, что во-первых, надо строить эту таблицу, а во-вторых, внутри структур заводить поле, сигнализирующее о том, какого она типа, и следить за тем, чтобы это поле содержало правильное значение.


В C++ всем этим занимается компилятор: достаточно обозначить функцию-метод как virtual, и для всех одноименных функций будет создана таблица и поле типа, за которыми следить будет опять-таки компилятор. Вам останется только пользоваться ими: при попыке вызвать функцию с таким именем, будет вызвана одна из серии одноименных функций в зависимости от типа структуры.

Различие 6. Исключения

Исключение по своей сути — это просто последовательность goto и return. Основан на обычной C-технологии setjmp/longjmp. try и catch — это setjmp с проверкой. throw — это longjmp. Когда вызывается throw, то проверяется: если он окажется внутри блока try, то выполняется goto на парный блок catch. Если нет, то делается return и ищется catch на уровень выше и так далее.

Наличие в throw/catch параметра ничего принципиально не меняет: и в обычном C можно было заполнить какие-то переменные перед вызовом longjmp и потом их проанализировать.

Различие 7. Перегруженные операторы

Относитесь к ним как к уродливым функциям и все станет ясно. a + b, где a и b — типа Point это функция от двух аргументов a и b, возвращающая Point:

Написать a+b равносильно вызову такой функции: operator+(a,b). Иногда эта технология удобна, а иногда вносит путаницу.

Различие 8. Ссылка

Многие программисты изучали C на основе языка Pascal. В Pascal есть возможность возвращать из функции больше одного параметра. Для этого применялось магическое слово «var». В C для того, чтобы сделать то же самое, приходилось расставлять в тексте уйму символов «*».

Разработчики C++ вняли стонам несчастных программистов и ввели слово var. А чтобы все это выглядел ооригинально, «var» они переименовали в «&» и назвали «ссылкой». Это вызвало большую путаницу, так как в C уже были понятия «указатель» (та самая звездочка) и «адрес» (обозначался тем же символом &), а понятие «ссылка» звучит тоже как что-то указующе-адресующее. Вот если бы, не мудрствуя лукаво, добавили слово var…

С одной стороны, использование ссылок намного сокращает текст программы. Но есть и неприятности. Во-первых, вызов функции, в которой параметр является ссылкой, выглядит так же, как вызов с обычным параметром. В результате «на глаз» незаметно, что параметр может измениться. А в C это заметно по значку &. Во-вторых, многочисленные звездочки в C напоминают программисту о том, что каждый раз выполняется дополнительная операция * разыменования указателя. Что побуждает сделать разумную оптимизацию. В C++ эти операции остаются незамеченными.

Различие 9. Inline, template и default-аргумент

Аргумент по-умолчанию — это то, о чем мечтали программисты C: чтобы иногда не надо было при вызове задавать некоторые параметры, которые в этом случае должны иметь некоторое «обычное» значение.

Желание программистов C контролировать типы параметров в define-ах породило в C++ inline-функции. Такая функция — это обычный define с параметрами, только не надо мучиться с символами «\» и проверяются типы.

Желание узаконить в параметрах define имя типа породило template. Главный плюс template — то, что #define с одинаковыми параметрами породит два одинаковых куска кода. А template в компиляторе скорее всего будет соптимизирован: одинаковые куски кода будут соединены в один. Имеется небольшой контроль типов по сравнению с #define, но не очень удобный.

В то же время template имеют ряд серьезных недостатков. Первый — ужасный, неудобный синтаксис. Чтобы это ощутить, достаточно попробовать. Уж лучше бы разрешили не контролировать типы некоторых параметров inline-функций. Второй недостаток — template остался так же неудобен при работе с отладчиком, как и #define.

Ну и последнее нововведение, продиктованное, видимо, все тем же стремлением избавиться от #define. Это — тип «имя поля» (pointer to member). В C удобно было применять имена полей структур в define. В C++ тоже самое можно сделать с помощью операторов ::*, .* и ->*. Например &Circle::radius — это имя поля radius структуры Circle, а Circle::*radius — соответствующий тип. Такую величину можно передать, как параметр. Фактически речь идет о смещении этого поля относительно начала структуры. Бывает полезно. Примерно так же можно передать адрес функции-метода.

Различие 10. Язык более высокого уровня?

Когда появились все эти нововведения, то многим стало видно то, что раньше было видно не столь многим. Это нормально: код упростился, а значит те его свойства, которые раньше были замаскированы лишними символами, стали заметны при меньшем напряжении мозгов. В этом и только в этом заключается более высокий уровень C++. Чуть больше абстракции, чуть меньше деталей — можно сосредоточится на более крупных блоках.

Существует мнение, что писать в стиле C на C++ — дурной стиль. Это мнение — всего лишь дань моде. Если в стиле C++ получается короче, лучше, надежнее, то глупо писать в стиле C. Это так, но верно и обратное!

Простой пример: у вас есть большой массив из 100 тысяч структур Point, который инициализируется один раз (все поля на 0) и много раз копируется в такие же массивы. Писать для элемента такого массива конструктор оказывается накладно. При его создании будет вызван конструктор для каждого элемента. Потом вы создадите массив, куда его надо копировать — и снова вызовы конструкторов. Затем вы выполняете копирование и затираете результаты второй инициализации. Мало того, что 100 тысяч вызовов конструктора просто не сопоставимы с одним вызовом memset, но эта серия вызовов будет повторяться не один раз, а много.

Такие примеры можно привести для каждого нововведения C++. Каждый плюс неизбежно тянет за собой минусы. Для хорошего программиста главным законом должна быть не мода, а конечный результат и трезвый расчет: что в данном конкретном случае выгоднее с точки зрения эффективности программы и времени, затраченного на ее разработку.

Что касается объектно-ориентированного программирования, то на самом деле оно не имеет никакого отношения к разнице между C и C++. Благодаря ряду усовершенствований, код на C++ компактнее и надежнее, чем на C. Часть этих усовершенствований связана с ООП, а часть — нет. Например, аргументы функций по-умолчанию и inline-функции к ООП не имеют никакого отношения. Они имеют отношение к ужесточению контроля типов.

ООП — это просто идея: «в зависимости от данных, выполнить процедуру». А ПОП (процедурно ориентированное программирование) — «в зависимости от процедуры изменить данные». Глупо молиться на ООП или на ПОП или отвергать что-то из них и тем более ужасаться при их смешивании. Разумно использовать тот и другое, смотря как будет точнее, проще, быстрее, компактнее.

Смешон консерватор, который говорит: «Я назло не буду использовать ООП, так как это — глупая новомодная штучка.» Такой консерватор обычно упрямо применяет только C и при этом не замечает, что давно пишет в стиле ООП, но на чистом C! Он думает, что раз он использует C, его никто не заподозрит в излишнем умничаньи.

Смешон модник, который говорит: «Я буду использовать ООП везде, так как хочу прослыть прогрессивным человеком, который быстро осваивает все новое!» Такой «передовик» упрямо применяет классы и template где надо и где не надо. Он громогласно вопит об ООП, но сколько-нибудь сложная часть его кода обычно написана в стиле ПОП: потому, что он ценит ООП только как признак прогрессивности, но не понимает простого смысла, заключенного в нем.

Отличия языков программирования C и C++

Концепция языка C++

С++ — язык общего назначения и задуман для того, чтобы настоящие программисты получили удовольствие от самого процесса программирования.

Язык программирования С++ задумывался как язык, который будет:

лучше и современней языка С;

поддерживать абстракцию данных;

поддерживать объектно-ориентированное программирование.

  • содержать большую и расширяемую стандартную библиотеку.
  • За исключением второстепенных деталей, он практически содержит язык С как подмножество (хотя есть пример программы, которая является программой на языке C, но не может быть скомпилирована на языке C++). Язык С расширяется введением гибких и эффективных средств, предназначенных для построения новых типов. Программист структурирует свою задачу, определив новые типы, которые точно соответствуют понятиям предметной области задачи. Такой метод построения программы обычно называют абстракцией данных. Информация о типах содержится в некоторых объектах типов, определенных пользователем. С такими объектами можно работать надежно и просто даже в тех случаях, когда их тип нельзя установить на стадии трансляции. Программирование с использованием таких объектов обычно называют объектно-ориентированным. Если этот метод применяется правильно, то программы становятся короче и понятнее, а сопровождение их упрощается.

    Ключевым понятием С++ является класс. Класс — это определяемый пользователем тип. Классы обеспечивают инкапсуляцию («упрятывание») данных, их инициализацию, неявное преобразование пользовательских типов, динамическое задание типов, контролируемое пользователем управление памятью и средства для перегрузки операций. В языке С++ концепции контроля типов и модульного построения программ реализованы более полно, чем в С. Кроме того, С++ содержит усовершенствования, прямо с классами не связанные: символические константы, функции-подстановки, стандартные значения параметров функций, перегрузка имен функций, операции управления свободной памятью и ссылочный тип. В С++ сохранены все возможности С эффективной работы с основными объектами, отражающими аппаратную «реальность» (разряды, байты, слова, адреса и т.д.). Это позволяет достаточно эффективно реализовывать пользовательские типы.

    Как язык, так и стандартные библиотеки С++ проектировались в расчете на переносимость. Имеющиеся реализации языка будут работать в большинстве систем, поддерживающих С. В программах на С++ можно использовать библиотеки С. Большинство служебных программ, рассчитанных на С, можно использовать и в С++.

    Можно сказать, что Си и С++ сосуществуют между собой. Когда в 2011 году вышел новый стандарт языка С++ — С++11, вместе с ним вышел и стандарт языка Си — С11.

    Заголовочные файлы стандартной библиотеки C++

    Все заголовочные файлы стандартной библиотеки языка C++ не содержат расширения .h. Например:

    Заголовочные файлы из стандартной библиотеки языка C можно использовать в языке C++, но их имена изменились — в начало файла добавилась буква «c», а расширение «.h» исчезло. То есть при желании использовать функции, которые в языке C определены в заголовочных файлах stdio.h или math.h, их требуется подключать следующим образом:

    Стандартная библиотека C++


    Язык C++ содержит обширную стандартную библиотеку.

    Основные части библиотеки следующие:

    1. Ввод-вывод описан в заголовочных файлах iostream, fstream и других.
    2. Работа со строками описана в файле string и других.
    3. Контейнеры (структуры данных) описаны в большом числе заголовочных файлов в соответствии с типом контейнера. Например, vector — динамический массив, set — множество с возможностью быстрого добавления, удаления, поиска элементов, map — ассоциативный массив (словарь), list — двусвязный список, stack — стек, queue — очередь.
    4. Алгоритмы (линейный и двоичный поиск, нахождение следующей перестановки, случайная перестановка) описаны в заголовочном файле algorithm.

    Первоначально часть стандартной библиотеки называлась STL — Standard Template Library и развивалась независимо от языка C++ компаниями HP и SGI. Затем она была добавлена в стандарт языка, но название STL сохранилось и часто употребляется применительно к той части библиотеки, которая относится к контейнерам и алгоритмам.

    Пространства имен

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

    Пространство имен объявляется так:

    namespace my_namespace
    <
    // Описание функций, переменных, классов
    int var;
    >;

    Для доступа к переменной var из пространства имен my_namespace нужно писать my_namespace::var . Можно также использовать инструкцию:

    using namespace my_namespace;

    тогда все имена из пространства имен my_namespace можно использовать без указания имени пространства имен (просто писать var ).

    Вся стандартная библиотека находится в пространстве имен std , поэтому нужно либо писать

    В нем объявлены объекты cin для ввода с клавиатуры и cout для вывода на экран.

    Чтобы считать со стандартного ввода значения переменных a, b, с, нужно написать:

    std::cin >> a >> b >> c;

    Для вывода на экран этих переменных нужно написать:

    std::cout std:: , если дать инструкцию using namespace std в начале программы.

    Комментарии в тексте программы

    В языке C допускались только многострочные комментарии. Начало комментария обозначалось символами /*, конец — символами */.

    /* Это комментарий.
    он может занимать несколько строк */

    В языке C++ появились однострочные комментарии — они отмечаются символами // и продолжаются до конца строки:

    int n; // Размер считываемого массива

    Cсылки

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

    Ссылку можно понимать как безопасный вариант указателя. При этом ссылки имеют особенности, отличающие их от указателей:

    1. При объявлении ссылка обязательно на уже существующий объект данного типа. Ссылка не может ссылаться «ни на что».
    2. Ссылка от её объявления до её исчезновения указывает на один и тот же адрес.
    3. При обращении к ссылке разыменование происходит автоматически.
    4. Адрес ссылки — это адрес исходного объекта, на который она указывает.

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

    int &x; // недопустимо!
    int &x = veryLongVariableName; // допустимо. Теперь x — это альтернативное имя переменной veryLongVariableName

    int A[10];
    int &x = A[5]; // Ссылка может указывать на элемент массива
    x++; // то же, что A[5]++;
    x = 1; // то же, что A[5] = 1;

    Передача параметров в функцию по ссылке

    Параметры можно передавать по ссылкам. При этом связывание ссылки с определённой переменной произойдёт в момент вызова функции (на этапе выполнения программы).

    x — логическое отрицание (НЕ)

    x & y — логическое умножение (И)

    x | y — логические сложение (ИЛИ)

    Для типа bool стираются различия между операторами && и & , а также между || и | .

    Совместимость с типом int

    Тип bool совместим с типом int по присваиванию в обе стороны.

    При этом true переходит в 1, false — в 0.

    При обратном приведении любое число, не равное нулю — переходит в true, 0 — в false.

    Если использовать bool в арифметическом выражении, то оно будет переведено в int: bool + bool = int.

    Надо понимать, что в С++ логический и целочисленный тип — это разные типы , поэтому по типу аргумента int и bool возможна перегрузка функций.

    Значения по умолчанию для параметров функций

    При объявлении функции можно назначить значение аргумента «по умолчанию». Если этот аргумент не будет задан, то функция будет использовать значение «по умолчанию).

    int factorial(int n=0)


    Если вызывать функцию без параметров, то значение параметра n будет равно 0.

    «По умолчанию» можно передавать только последние параметры функции. Например, объявим функцию так:

    Эту функцию можно вызвать от одного, двух, или трех параметров. Если вызвать ее от одного параметра, то будет передано значение x, а значения y и z возьмутся «по умолчанию» и будут равны 1 и 2. Если вызвать от 2 параметров — то будут заданы значения x и y, а значение z будет равно 2.

    const-объявления

    В языке C для объявления констант использовались директивы препроцессора #define. Например:

    Это низкоуровневый и опасный механизм. Например, объявленную таким образом константу на самом деле можно переопределить:

    В языке C++ появились константные выражения, которые нужно использовать вместо #define:

    const int N = 100;

    Кроме того, слово const используется при описании параметров функции вместе со ссылками для объявления «константных ссылок» — объект передается в функцию по ссылке, а не по значению (то есть не создается копия объекта, что важно для больших контейнеров, копирование которых может занимать много времени), но при этом функция не может модифицировать передаваемый объект.

    Работа с динамической памятью

    Для работы с динамической памятью вместо функций malloc и free языка C в языке C++ введены операторы new и delete. Использование функций языка C для работы с динамической памятью не рекомендуется в языке C++

    10 фич в C#, о которых вы определённо должны узнать и начать их использовать

    Если вы только начали изучение C# или же решили расширить свои знания, мы нашли для вас 10 фич, знание которых позволит вам избежать ошибок, писать более понятный код и сохранить кучу времени.

    1. async / await

    Использование паттернов async / await позволяет разблокировать UI / текущий поток во время выполнения блочных операторов. Паттерны async / await позволяют коду продолжить выполнение, даже если что-то блокирует его выполнение (например, веб-запрос).

    2. Инициализаторы объектов / массивов / коллекций

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

    3. Лямбды, предикаты, делегаты и замыкания

    Эти фичи просто незаменимы во многих случаях: например, при использовании LINQ. Поэтому рекомендуем вам убедиться, что вы действительно понимаете, когда и как их использовать.

    4. ?? (Оператор объединения с NULL)

    x ?? y — возвращает x , если значение отличается от null ; в противном случае возвращает y .

    Может быть несколько операторов .

    ?? также может быть использован для перевода типов null в не null :

    5. $”” (Интерполяция строк) — C# 6

    Фича в C# 6 позволяет эффективно и элегантно собирать строки:

    6. ?.(определяет null) — C# 6

    x?.y — доступ к членам, определяемый условием null . Возвращает значение null , если левый операнд имеет значение null .

    Больше никаких NullReferenceExceptions!

    7. Выражение nameof — C# 6

    Может показаться, что выражение nameof не особо полезно, но это не так. При использовании автоматических инструментов рефакторинга (например, ReSharper) иногда может потребоваться обратиться к аргументу метода по его имени:

    Вот, как это должно быть:

    8. Инициализаторы свойств (property) — C# 6

    Инициализаторы свойств позволяют задавать начальные значения для свойств:

    Польза их использования заключается в том, что вы не можете объявить setter, тем самым делая свойства неизменяемыми. Инициализаторы свойств хорошо работают в связке с синтаксисом первичного конструктора в C# 6.

    9. Операторы as и is

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

    As — преобразование типов. Возвращает левый операнд, приведенный к типу, заданному правым операндом (статический тип), но as возвращает null , где (T)x вызывает исключение.

    10. Ключевое слово yield

    Ключевое слово yield позволяет заполнить интерфейс IEnumerable объектами (items). Следующий пример вернет все степени двойки от 2 до 2 в степени 8 (то есть 2, 4, 8, 16, 32, 128, 256):

    В правильных руках yield — очень мощная вещь. Оно позволяет с легкостью генерировать последовательность объектов, то есть системе не придется перечислять всю коллекцию целиком — это может быть сделано по требованию.

    Логические операторы (справочник по C#) Boolean logical operators (C# reference)

    Следующие операторы выполняют логические операции с использованием логических операндов: The following operators perform logical operations with the bool operands:

    • Унарный ! (логическое отрицание) оператор. Unary ! (logical negation) operator.
    • Бинарные & (логическое И), | (логическое ИЛИ), а также ^ (логическое исключающее ИЛИ) операторы. Binary & (logical AND), | (logical OR), and ^ (logical exclusive OR) operators. Эти операторы всегда обрабатывают оба операнда. Those operators always evaluate both operands.
    • Бинарные && (условное логическое И) и || (условное логическое ИЛИ) операторы. Binary && (conditional logical AND) and || (conditional logical OR) operators. Эти операторы вычисляют правый операнд, только если это необходимо. Those operators evaluate the right-hand operand only if it’s necessary.

    Для операндов целочисленных типов операторы & , | и ^ выполняют побитовые логические операции. For the operands of the integral types, the & , | , and ^ operators perform bitwise logical operations. Дополнительные сведения см. в разделе Побитовые операторы и операторы сдвига. For more information, see Bitwise and shift operators.


    Оператор логического отрицания ! Logical negation operator !

    Унарный префиксный оператор ! выполняет логическое отрицание операнда, The unary prefix ! operator computes logical negation of its operand. возвращая true , если операнд имеет значение false , и false , если операнд имеет значение true . That is, it produces true , if the operand evaluates to false , and false , if the operand evaluates to true :

    Начиная с C# 8.0, унарный постфиксный оператор ! допускает значение NULL. Starting with C# 8.0, the unary postfix ! operator is the null-forgiving operator.

    Оператор логического И & Logical AND operator &

    Оператор & вычисляет логическое И для всех своих операндов. The & operator computes the logical AND of its operands. Результат операции x & y принимает значение true , если оба оператора x и y имеют значение true . The result of x & y is true if both x and y evaluate to true . В противном случае результат будет false . Otherwise, the result is false .

    Оператор & вычисляет оба операнда, даже если левый операнд имеет значение false и результат должен принять значение false , независимо от значения правого операнда. The & operator evaluates both operands even if the left-hand operand evaluates to false , so that the result must be false regardless of the value of the right-hand operand.

    В следующем примере правый операнд оператора & является вызовом метода, который выполняется независимо от значения левого операнда: In the following example, the right-hand operand of the & operator is a method call, which is performed regardless of the value of the left-hand operand:

    Условный оператор логического И && также вычисляет логическое И для своих операндов, но не вычисляет правый операнд, если левый операнд имеет значение false . The conditional logical AND operator && also computes the logical AND of its operands, but doesn’t evaluate the right-hand operand if the left-hand operand evaluates to false .

    Для операндов целочисленного типа оператор & вычисляет побитовое логическое И своих операндов. For the operands of the integral types, the & operator computes the bitwise logical AND of its operands. Унарный оператор & является оператором AddressOf. The unary & operator is the address-of operator.

    Оператор логического исключения ИЛИ ^ Logical exclusive OR operator ^

    Оператор ^ вычисляет логическое исключение ИЛИ для всех своих операндов, The ^ operator computes the logical exclusive OR, also known as the logical XOR, of its operands. возвращая true для x ^ y , если x имеет значение true и y имеет значение false или x имеет значение false и y имеет значение true . The result of x ^ y is true if x evaluates to true and y evaluates to false , or x evaluates to false and y evaluates to true . В противном случае результат будет false . Otherwise, the result is false . То есть для операндов bool оператор ^ возвращает тот же результат, что и оператор неравенства != . That is, for the bool operands, the ^ operator computes the same result as the inequality operator != .

    Для операндов целочисленного типа оператор ^ вычисляет побитовое логическое исключающее ИЛИ своих операндов. For the operands of the integral types, the ^ operator computes the bitwise logical exclusive OR of its operands.

    Оператор логического ИЛИ | Logical OR operator |

    Оператор | вычисляет логическое ИЛИ для всех своих операндов. The | operator computes the logical OR of its operands. Результат операции x | y принимает значение true , если хотя бы один из операторов x или y имеет значение true . The result of x | y is true if either x or y evaluates to true . В противном случае результат будет false . Otherwise, the result is false .

    Оператор | вычисляет оба операнда, даже если левый операнд имеет значение true и результат должен принять значение true , независимо от значения правого операнда. The | operator evaluates both operands even if the left-hand operand evaluates to true , so that the result must be true regardless of the value of the right-hand operand.

    В следующем примере правый операнд оператора | является вызовом метода, который выполняется независимо от значения левого операнда: In the following example, the right-hand operand of the | operator is a method call, which is performed regardless of the value of the left-hand operand:

    Условный оператор логического ИЛИ || также вычисляет логическое ИЛИ для своих операндов, но не вычисляет правый операнд, если левый операнд имеет значение true . The conditional logical OR operator || also computes the logical OR of its operands, but doesn’t evaluate the right-hand operand if the left-hand operand evaluates to true .

    Для операндов целочисленного типа оператор | вычисляет побитовое логическое ИЛИ своих операндов. For the operands of the integral types, the | operator computes the bitwise logical OR of its operands.

    Условный оператор логического И && Conditional logical AND operator &&

    Условный оператор логического И && (оператор короткого замыкания) вычисляет логическое И для своих операндов. The conditional logical AND operator && , also known as the «short-circuiting» logical AND operator, computes the logical AND of its operands. Результат операции x && y принимает значение true , если оба оператора x и y имеют значение true . The result of x && y is true if both x and y evaluate to true . В противном случае результат будет false . Otherwise, the result is false . Если x имеет значение false , y не вычисляется. If x evaluates to false , y is not evaluated.

    В следующем примере правый операнд оператора && является вызовом метода, который не выполняется, если левый операнд имеет значение false : In the following example, the right-hand operand of the && operator is a method call, which isn’t performed if the left-hand operand evaluates to false :

    Оператор логического И & также вычисляет логическое И для своих операндов, но он всегда вычисляет оба операнда. The logical AND operator & also computes the logical AND of its operands, but always evaluates both operands.

    Условный оператор логического ИЛИ || Conditional logical OR operator ||

    Условный оператор логического ИЛИ || (оператор короткого замыкания) вычисляет логическое ИЛИ для своих операндов. The conditional logical OR operator || , also known as the «short-circuiting» logical OR operator, computes the logical OR of its operands. Результат операции x || y принимает значение true , если хотя бы один из операторов x или y имеет значение true . The result of x || y is true if either x or y evaluates to true . В противном случае результат будет false . Otherwise, the result is false . Если x имеет значение true , y не вычисляется. If x evaluates to true , y is not evaluated.

    В следующем примере правый операнд оператора || является вызовом метода, который не выполняется, если левый операнд имеет значение true : In the following example, the right-hand operand of the || operator is a method call, which isn’t performed if the left-hand operand evaluates to true :

    Оператор логического ИЛИ | также вычисляет логическое ИЛИ для своих операндов, но всегда вычисляет оба операнда. The logical OR operator | also computes the logical OR of its operands, but always evaluates both operands.

    Операторы, допускающие логическое значение NULL Nullable Boolean logical operators

    Для операндов bool? операторы & и | поддерживают троичную логику. For the bool? operands, the & and | operators support the three-valued logic. Семантика этих операторов определяется по следующей таблице: The semantics of these operators is defined by the following table:

    п x y y x&y x&y x|y x|y
    true true true true true true true true
    true true Ложь false false false true true
    true true null null null null true true
    Ложь false true true Ложь false true true
    Ложь false Ложь false Ложь false Ложь false
    Ложь false null null Ложь false null null
    null null true true null null true true
    null null Ложь false Ложь false null null
    null null null null null null null null

    Поведение этих операторов отличается от типичного поведения операторов, допускающих значение NULL. The behavior of those operators differs from the typical operator behavior with nullable value types. Как правило, оператор, который определяется для операндов типа значения, можно также использовать с соответствующими операндами типа, допускающего значение NULL. Typically, an operator which is defined for operands of a value type can be also used with operands of the corresponding nullable value type. Такой оператор возвращает null , если какой-либо из операндов имеет значение null . Such an operator produces null if any of its operands is null . При этом операторы & и | могут возвращать отличное от NULL значение, даже если один из операндов имеет значение null . However, the & and | operators can produce non-null even if one of the operands is null . См. подробнее о поведении операторов, допускающих значение NULL, в руководстве по использованию типов, допускающих значение NULL. For more information about the operator behavior with nullable value types, see the Operators section of the Using nullable value types article.

    Вы также можете также использовать операторы ! и ^ с операндами bool? , как показано в следующем примере: You can also use the ! and ^ operators with the bool? operands, as the following example shows:

    Условные логические операторы && и || не поддерживают операнды типа bool? . The conditional logical operators && and || don’t support the bool? operands.

    Составное присваивание Compound assignment

    Для бинарного оператора op выражение составного присваивания в форме For a binary operator op , a compound assignment expression of the form

    эквивалентно is equivalent to

    за исключением того, что x вычисляется только один раз. except that x is only evaluated once.

    Операторы & , | и ^ поддерживают составное присваивание, как показано в следующем примере: The & , | , and ^ operators support compound assignment, as the following example shows:

    Условные логические операторы && и || не поддерживают составное присваивание. The conditional logical operators && and || don’t support compound assignment.

    Приоритет операторов Operator precedence

    В следующем списке перечислены логические операторы в порядке убывания приоритета: The following list orders logical operators starting from the highest precedence to the lowest:

    • Оператор логического отрицания ! Logical negation operator !
    • Оператор логического И & Logical AND operator &
    • Оператор логического исключающего ИЛИ ^ Logical exclusive OR operator ^
    • Оператор логического ИЛИ | Logical OR operator |
    • Условный оператор логического И && Conditional logical AND operator &&
    • Условный оператор логического ИЛИ || Conditional logical OR operator ||

    Порядок вычисления, определяемый приоритетом операторов, можно изменить с помощью скобок ( () ). Use parentheses, () , to change the order of evaluation imposed by operator precedence:

    Полный список операторов C#, упорядоченных по уровню приоритета, см. в статье Операторы C#. For the complete list of C# operators ordered by precedence level, see C# operators.

    Возможность перегрузки оператора Operator overloadability

    Определяемый пользователем тип может перегружать операторы ! , & , | и ^ . A user-defined type can overload the ! , & , | , and ^ operators. При перегрузке бинарного оператора соответствующий оператор составного присваивания также неявно перегружается. When a binary operator is overloaded, the corresponding compound assignment operator is also implicitly overloaded. Определяемый пользователем тип не может перегружать оператор составного присваивания явным образом. A user-defined type cannot explicitly overload a compound assignment operator.

    Определяемый пользователем тип не может перегружать условные логические операторы && и || . A user-defined type cannot overload the conditional logical operators && and || . При этом, если определяемый пользователем тип каким-либо образом перегружает операторы true и false и операторы & и | , операция && или || может быть применена для операндов этого типа. However, if a user-defined type overloads the true and false operators and the & or | operator in a certain way, the && or || operation, respectively, can be evaluated for the operands of that type. Дополнительные сведения см. в разделе Пользовательские условные логические операторы в Спецификации языка C#. For more information, see the User-defined conditional logical operators section of the C# language specification.

    Спецификация языка C# C# language specification

    Дополнительные сведения см. в следующих разделах статьи Спецификация языка C#: For more information, see the following sections of the C# language specification:

    Илон Маск рекомендует:  Долгоиграющий Cowon D20. Обзор характеристик
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL