?

Log in

No account? Create an account
   Journal    Friends    Archive    Profile    Memories
 

C++ - morfizm


Oct. 18th, 2018 01:18 am C++

В порядке ликбеза, для начинающих программистов на C и C++: (сначала написал в комментарии, но решил вынести в пост - вдруг кому пригодится)

Ассемблер, C и C++ - это всё линейка языков, позволяющих выжать максимум производительности из процессора. Почти все языковые фичи с идут минимальным overhead'ом, и так, чтобы можно было писать код с полным пониманием, какие переменные и структуры данных влезут в cache lines процессора, и т.п.

Традиционно эффективнее всего было писать на ассемблере, потому что на нём можно делать всякие трюки, до которых компилятор сей не догадается. Зато на C можно думать модульно и писать на чуть более высоком уровне, компактнее (циклы, а не условные переходы вверх, многомерные массивы, а не сложное вычисление индекса в одномерном и т.п.). Но когда мы пишем a[i][j], мы, конечно, понимаем, что в памяти это представляется как одномерный массив, "a" это указатель на его начало, и a[i][j] это эквивалент a + i*N + j, где N это количество строк в объявлении массива (a[N][M]). Мало того, мы понимаем, что операция + с указателями, на самом деле инкрементирует указатель не на указанное число, а на количество байт, которые занимает тип, на который указатель указывает. Т.е. если у нас long a[N][M], то i*N + j это количество long-ов, а в байтах будет 4*(i*N + j).

Ещё один плюс языка C - его (как бы) кроссплатформенность. Именно потому что не нужно нигде hard-code это число 4, можно написать "int" и на какой-то архитектуре он будет 2-байтовый, а на какой-то 4-байтовый, а работать будет корректно и в одном, и в другом случае. (Просто в случае 2-байтового быстрее будет возникать переполнение). Но компилятор скомпилирует разный код (разный ассемблер) в зависимости от платформы. Где-то индексы будут умножаться на 2, а где-то на 4.

C++ это шаг дальше. Это попытка помочь упростить жизнь, когда используешь объектно-ориентированную парадигму. В принципе, ООП можно использовать и на C, просто придётся ручками передавать параметр "this" как ссылку на структуру во все функции, придётся явно обращаться к полям, разыменовывая this, придётся заводить таблицу виртуальных методов в виде массива указателей на фукнции. C++ даёт синтаксис, позволяющий перенести всю эту нудную работу на компилятор. Но тот, кто пишет на C++, прекрасно понимает, как оно будет скомпилировано, и как бы можно было то же самое написать на C. Просто будет громоздко.

Современный C++ (C++ 11/14) - это очередной революционный переход дальше по той же лестнице, в котором добавляется синтаксис для модной нынче функциональной парадигмы (и позволяющей ещё компактнее писать интересные алгоритмы и логику программы), при этом C++ сохраняет традицию генерировать только самый-пресамый прожиточный минимум кода (который ты явно написал бы сам, если бы всё то же самое имплементировал на C), и от некоторых sexy фич C++ отказывается, потому что они не позволяют писать код, оптимальный для процессора.

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

Короче, C и C++ это непростые языки программирования. За ними должно идти глубокое понимание архитектуры процессора и памяти, желание писать оптимальный для процессора код, необходимость писать этот код из-за CPU-bound задач (heavy computation, low latency, heavy real-time, etc). C++ позволяет программисту примирить все модные концепты и парадигмы, позволяющие разрабатывать софт быстро, и желание всё оптимизировать на ассемлерном уровне, чтобы оно ещё и быстро работало.

Тем не менее, если задача оптимизации процессора не стоит, то на Java можно писать примерно в 10 раз быстрее (по времени программиста), чем на C++, даже со всеми его современными приблудами, облегчающими жизнь.

10 comments - Leave a commentPrevious Entry Share Next Entry

Comments:

From:eternele
Date:October 18th, 2018 02:50 pm (UTC)
(Link)
like
From:andreyvo
Date:October 18th, 2018 02:58 pm (UTC)
(Link)
JIT ну и LLVM в теории еще лучше может заоптимизировать код.
C++ - это такакя прикольная вещь для стрельбы в себе в ногу. Если уж писать низкоуровневое - то на C. Или Rust или Kotlin/Native
From:eternele
Date:October 18th, 2018 06:55 pm (UTC)
(Link)
Пацталом
From:birdwatcher
Date:October 18th, 2018 03:04 pm (UTC)
(Link)
Как это на Джаве можно написать что-то в десять раз быстрее? Я так быстро печатать-то не смогу.
From:morfizm
Date:October 18th, 2018 06:10 pm (UTC)
(Link)
Я имел в виду, общий цикл написания чего-то и выкатывания в продакшен. Типа 1 неделя vs 10.

Впрочем, быстрый typing это тоже тема:
https://www.youtube.com/watch?v=HA71Y1jttSc
From:birdwatcher
Date:October 18th, 2018 06:33 pm (UTC)
(Link)
Что-то сомнительно. Проблема в том, чтобы знать, что написать и как протестировать, а не на каком языке. В конце концов, всегда можно программиста нанять.
From:freeborn
Date:October 18th, 2018 08:34 pm (UTC)
(Link)
якобы слов получится в 10 раз меньше, хотя сами слова будут в 10 раз длиннее, пока все эти AbstractCheckedFutureBuilderFactoryVisitorInjector напечатаешь, уже С++ выучить можно %)
From:metaller
Date:October 19th, 2018 11:05 am (UTC)
(Link)
Прямо так и вижу Диму читающего лекцию в Progmeistars ;)
From:archaicos
Date:October 19th, 2018 11:09 am (UTC)
(Link)
> Ещё один плюс языка C - его (как бы) кроссплатформенность. ... можно написать "int" и на какой-то архитектуре он будет 2-байтовый, а на какой-то 4-байтовый, а работать будет корректно и в одном, и в другом случае.

Пока не выучишь стандарт языка, ключевым является «как бы», т.к. «работать будет корректно» только если повезёт.
From:archaicos
Date:October 19th, 2018 11:27 am (UTC)
(Link)
> C++ это шаг дальше. Это попытка помочь упростить жизнь, когда используешь объектно-ориентированную парадигму.

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

Ещё одна заковыка в C++ в том, что это язык, позволяющий писать «скомпрессированный» код. Некое foo или = может скрывать за собой очень много чего. Страницы кода. Это часто бывает частным случаем плохого ООП (когда не просто много кода, а большая его часть почти лишена смысла, и время тратится на разбор этих пустот). Но и это само по себе не является проблемой.

Это всё лишь отягчающие обстоятельства. Основная проблема в том, что до сих пор нету никакого IDE для нахождения всех концов в большом проекте. С учётом макросов и зоопарка систем сборки (make, cmake и пр.). VS, кмк, весьма далёк от идеала, хоть и бьёт всё или почти всё прочее.