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

  1. Языки несовместимы и уже давно. Они развиваются параллельно(хотя про развитие стандарта С не знает ничего даже гугл, но он есть, добавили дженерики и хотят лямбды...)

  2. Громадная часть С кода хоть и компилируется в С++, но является undefined behavior. В первую очередь из-за того, что все типы в С являются тупым набором байт и никакая эмуляция полиморфизма здесь не поможет. Язык позволяет относится со всем как с байтами, тогда как в С++ все типы это объекты инкапсулирующие свою логику через конструкторы и деструкторы, есть понятие лайфтайма, относится как к байтам можно только к тривиально копируемым объектам и то не всегда и не везде, только в С++20 валидно было бы реинтерпретировать байты как int, а в С коде это происходит повсеместно.

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

  3. Самое главное - языки требуют абсолютно разных умений и подходов к разработке.

С - фактически императивный язык структурного программирования(да и с этим можно поспорить из-за обилия goto в некоторых проектах). Он не предполагает никакой декларативности, полиморфизма, инкапсуляции, иммутабельности и прочих модных слов. Его сфера использования это места, где нет С++ компилятора(глубокий наколеночный эмбед)

Современный С++ в свою очередь это во многом декларативный и функциональный - шаблоны, алгоритмы, итераторы и ренжи, RAII - язык с элементами ООП в виде инкапсуляции логики в объекты(типа вектора) или наследования для реализации чего-то(но почти никогда не так, чтобы пользователь абстракции знал что она реализована через наследование). Писать что-то в императивном стиле в современном С++ просто странно.

Эти подходы(декларативный и императивный) фактически противоположны, поэтому разработчик на С++ будет с трудом писать на С, а разработчик на С, как показывает практика, вообще не сможет писать в стиле С++

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

Давайте уже одумаемся.

Комментарии (307)


  1. funca
    13.07.2022 19:42
    +39

    Как и Java/JavaScript


    1. iago
      13.07.2022 20:45
      +26

      Вы не поверите, но в 2019 году помню, на огромной американской корпорации на курилке разговаривал с JS-разработчиком. И он мне рассказывал что Java - это браузерный движок для работы JavaScript. Помню, у меня тогда так же подгорало как у автора этого поста


      1. Jian
        14.07.2022 07:16
        +6

        Путаница из-за того, что VB-script - это действительно браузерный движок для работы Visual Basic в Internet Explorer. :)


        1. tyomitch
          14.07.2022 09:10
          +1

          VBScript от Visual Basic отличается примерно так же, как JavaScript от Java: синтаксис немного похож, на этом сходства заканчиваются.


          1. charypopper
            14.07.2022 15:52
            +2

            когда учишь ЯП, особенно первые - то сходство синтаксиса первично, чтобы сказать что языки похожи. И людей которые "плохо знают"* язык гораздо больше чем людей которые "хорошо знают"** язык, а людей которые используют эти термины и "вообще не знают" язык - соизмеримо, имхо. из этого и выходит c/c++, т.к. реальность формируют не только умельцы, но и те кто дают базу, сворачивают с разработки, конкретно с этих ЯП и тд. Даже взять если хабр, автора статьи поймут многие, но сколько статей и комментов написано с подачи что c/c++ похожи. Плюс есть еще "с-подобность", да и сравнение идет с этими ЯП т.к. их давали многим кто в итоге остается в программировании.

            *, ** - абстрактная субъективщина с тысячей около истинных определений


        1. Arsmerk_true
          14.07.2022 09:40

          а как же VA-script?

          https://habr.com/ru/post/554014/


        1. funca
          14.07.2022 12:13
          +2

          В свое время Microsoft'у запрещали называть свой интерпретатор словом JavaScript из-за того, что они пытались творить там несовместимые вещи. Поэтому язык назывался JScript. VbScript и JScript входили в состав компонента Windows Script Host (WSH), но также были доступны из IE.


          1. Jian
            14.07.2022 12:29

            J++, который двигала Microsoft, был на основе java-script, или на основе java?


            1. DMGarikk
              14.07.2022 13:07

              Java, из-за чего они помоему с sun судились в итоге тоже


    1. in_heb
      13.07.2022 23:59
      +5

      видимо это обозначение фулстэк разработчика


    1. GospodinKolhoznik
      14.07.2022 07:21
      +3

      Но уж язык Java/Kotlin точно существует?


      1. Xobotun
        14.07.2022 08:18
        +2

        Тогда уж Java/Lombok. Это действительно уже диалект джавы, как мне кажется.


        1. RyAtex
          15.07.2022 14:45

          Lombok это библиотека. Тогда уж праильне сказать Java/Spring


        1. loltrol
          16.07.2022 10:19

          Не согласен. Код на ломбоке это ситаксически-верный код java. Если бы lombok добавлял бы парочку новых keyword'ов, тогда другое дело.


  1. nanev1976
    13.07.2022 19:55
    +13

    Не-а. C это подмножество C++, ровно как и подмножество Objective-C. Компании ищут "C/C++" так как программисту часто (всегда) будет нужно работать с "тупыми наборами байт" и что еще хуже, взаимодействовать с железом (даже если посредством толстого фреймворка типа CUDA Toolkit). Если этого нет, то писать на C/C++ не имеет никакого смысла, для бизнес логики есть всякие сишарпы с джавами.


    1. Kelbon Автор
      13.07.2022 20:06
      +21

      только часть С это подмножество С++
      А с точки зрения хорошего С++ кода практически ничего из С использовать не нужно


      1. Chaos_Optima
        13.07.2022 20:34
        +34

        Видимо геймдев не в курсе. А то там постоянно парятся над выравниванием байтиков, алокациями и прочим менеджментом памяти.

        Кстати ООП также преимущественно является императивным стилем, как и функциональное программирование. Я честно говоря ещё ни разу за 12 лет не видел в С++ декларативного программирования, или для вас использование готовых библиотек является декларативным программированием?


        1. Kelbon Автор
          13.07.2022 20:38
          -6

          А как связаны аллокации и С?


          1. Chaos_Optima
            13.07.2022 21:22
            +10

            Я имею ввиду написание своих аллокаторов, что по моему мнению напрямую схоже с С way


            1. domix32
              13.07.2022 22:31
              +4

              И это не считая что существует куча именно Сишных зависимостей, типа того же curl или openal. Да те же pthreads/epoll и все что их окружает. И в мире С++ они появляются заметно чаще, чем хотелось бы. Потому оно и С/С++.


              1. lorc
                13.07.2022 23:07
                +2

                Я вообще не уверен что в C++ можно открыть сокет и послать пакет без reinterpret_cast или там C-style cast. На этапе connect уже возникнут проблемы.


                1. domix32
                  14.07.2022 00:29
                  +4

                  Как-то так до сих пор и нет std::network в библиотеке. Всё остальное из cstd подключают.


                  1. Kelbon Автор
                    14.07.2022 06:59
                    -1

                    подключают boost::asio, а не сишные сокеты


                    1. DabjeilQutwyngo
                      14.07.2022 09:19
                      +5

                      Открыл исходник v69 по пути "detail/impl/socket_ops.ipp":

                      ...
                      #include <cctype>
                      #include <cstdio>
                      #include <cstdlib>
                      #include <cstring>
                      #include <cerrno>
                      #include <new>
                      #include <boost/asio/detail/assert.hpp>
                      #include <boost/asio/detail/socket_ops.hpp>
                      #include <boost/asio/error.hpp>
                      ...
                      template <typename SockLenType>
                      inline socket_type call_accept(SockLenType msghdr::*,
                          socket_type s, socket_addr_type* addr, std::size_t* addrlen)
                      {
                        SockLenType tmp_addrlen = addrlen ? (SockLenType)*addrlen : 0;
                        socket_type result = ::accept(s, addr, addrlen ? &tmp_addrlen : 0);
                        if (addrlen)
                          *addrlen = (std::size_t)tmp_addrlen;
                        return result;
                      }
                      

                      ::accept -- тот самыйacceptдля сишного сокета.


                      1. Kelbon Автор
                        14.07.2022 09:23
                        -5

                        это не сишный сокет, а платформозависимый, вы бы ещё сказали "открыл .exe, там машинный код"


            1. Kelbon Автор
              14.07.2022 08:30
              -5

              Аллокатор в С и аллокатор в С++ это совершенно разные вещи.

              С++ аллокатор это абстракция, легковесный объект предоставляющий интерфейс для получения памяти.


              1. Chaos_Optima
                14.07.2022 12:53

                Ну ок чем отличается по вашему

                //C++
                auto data = Allocate<Data>();
                // от С
                struct DataHandle* data = ALLOCATE(Data);

                Внутри ведь они могут будут устроены практически одинаково.


                1. Kelbon Автор
                  14.07.2022 13:09
                  -6

                  Вы понятия не имеете как выглядит аллокатор в С++

                  Спойлер

                  ВОТ ТАК

                  template<typename T, typename Alloc = std::allocator<T>>
                  struct vector { ... };


                  1. Chaos_Optima
                    14.07.2022 13:58

                    facepalm Я говорю про реализацию аллокаторов а не про использование их в дальнейшем, видно вы никогда не писали свои аллокаторы. Ладно хотите пример применения на подобие С++ ок

                    struct vector = create_vector(ALLOCATOR_FOR(Data));
                    ...
                    struct Data item = at(vector, i);


                    1. Kelbon Автор
                      14.07.2022 14:00

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

                      Ассемблер ужасен, да и всё равно не вы сможете реализовать полноценный вектор. Просто попробуйте и поймете, что С не даст вам этого сделать


                      1. Chaos_Optima
                        14.07.2022 15:27

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

                        Простите, но указанный аллокатор в векторе создаётся разве не в рантайме? Точно также создаётся в рантайме, а ещё его можно передать конструктору вектора. Но самое главное, речь была не про использование аллокатора, а про устройство аллокатора, как он внутри устроен, вы упорно это игнорируете и пытаетесь свинтить в другую тему.


                      1. Kelbon Автор
                        14.07.2022 15:38
                        +1

                        Нет не в рантайме. Стандартный аллокатор не занимает там места вообще, кастомный с состоянием может занимать состояние и подставляться на рантайме


                      1. Chaos_Optima
                        14.07.2022 15:47

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


                      1. Kelbon Автор
                        14.07.2022 16:10
                        +2

                        и как вы это реализуете?


                    1. 0xd34df00d
                      14.07.2022 16:23

                      Если вы говорите про реализацию аллокатора, то на чистом стандартном C написать аллокатор (и вообще malloc) умнее, чем «выделить из статического массива» нельзя. Что это говорит о связи C и, не знаю, ассемблера?


                      1. Chaos_Optima
                        14.07.2022 16:29

                        Почему нельзя? У гуглов и интелов получилось вроде. Правда не до конца понимаю что вы имели ввиду.


                      1. 0xd34df00d
                        14.07.2022 16:29

                        И они там в итоге не дёргают ядро, которое в итоге утыкается в ассемблер?


                      1. lorc
                        14.07.2022 16:40

                        Ну так с ядра все начинается и им же все заканчивается. Какая разница, прочитает - ядерный загрузчик размер секции .bss из ELF для того чтобы выделить кусок памяти или само приложение вызовет mmap(ANONYMOUS) чтобы получить себе памяти в свое адресное пространство?

                        Рантайм любого языка будет дергать ядерные вызовы типа mmap или sbrk(не к ночи будь упомянут) чтобы получить память от ядра для своего внутреннего аллокатора.


                      1. 0xd34df00d
                        14.07.2022 16:44

                        А внутри mmap или sbrk что происходит? В итоге написанный на ассемблере код вызывается, не так ли?


                      1. lorc
                        14.07.2022 17:01

                        Вы удивитесь, но скорее всего нет. Если продраться через абстракции, то все сводится к записи в таблицу трансляции MMU. Прямо из сишного кода. Что-то типа page_table[virtual_addr] = physical_addr.

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


                      1. flx0
                        14.07.2022 17:11

                        А как по-вашему ядро знает какие у него физические страницы заняты, а какие свободны?


                      1. lorc
                        14.07.2022 17:17

                        Ну как.... У него есть свой аллокатор страниц. Который следит за тем, какие страницы кому были выданы.


                      1. 0xd34df00d
                        14.07.2022 17:14
                        +4

                        1. Откуда берётся физический адрес?
                        2. Какое место в стандарте C гарантирует, что оттуда можно читать и туда можно писать?
                        3. Как это всё работает с оверкоммитом и выделением страниц по мере обращения к ним? Какие сишные конструкции или функции из стандарта в итоге это позволяют?


                      1. lorc
                        14.07.2022 17:45

                        Откуда берётся физический адрес?

                        Из аллокатора страниц. Аллокатор знает где вообще расположена память потому что ему об этом сказал условный BIOS.

                        Какое место в стандарте C гарантирует, что оттуда можно читать и туда можно писать?

                        А это самая банальная память. Туда можно писать и оттуда можно читать как угодно.

                        Вы наверное спрашиваете про Memory Mapped IO, которые хоть и выглядят как память, но ею не является. Поэтому ядро кстати туда на пишет через a = 17. Есть специальные функции обертки: writel(a, 17). Которые с одной стороны обламывают шибко умный компилятор, и с другой - обеспечивают совместимость со стандартом. (А вот всякий код на arduinо пишет в лоб. Стыд и позор им.)

                        Как это всё работает с оверкоммитом и выделением страниц по мере обращения к ним? Какие сишные конструкции или функции из стандарта в итоге это позволяют?

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

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

                        Ядро же - это отдельная сущность. Отдельная абстрактная машина с точки зрения стандарта. Для ядра - операции над page tables приложения выглядят как просто работа с массивом структур. Стандарт это позволяет, надеюсь :)


                      1. 0xd34df00d
                        14.07.2022 18:16
                        +2

                        Аллокатор знает где вообще расположена память потому что ему об этом сказал условный BIOS.

                        Как сказал? Какая сишная функция отвечает за взаимодействие с BIOS?


                        А это самая банальная память. Туда можно писать и оттуда можно читать как угодно.

                        Вы утверждаете, что я могу написать


                        int *ptr = (int*) 0xd34df00d;
                        printf("%d\n", *ptr);

                        и это будет валидный сишный код?


                        Я утверждаю, что нет. Более того, я утверждаю, что это не факт что корректный C-код, даже если я знаю, что эта область памяти была раньше выделена каким-нибудь malloc, потому что pointer provenance.


                        А насчет стандарта — для приложения стандарт заканчивается в тот момент, когда оно дергает условный mmap или другой системный вызов. Потом происходит магия за пределами абстрактной машины описанной стандартом и мы получаем свой валидный указатель на void.

                        И я утверждаю, что эту магию невозможно реализовать на стандартном C.


                      1. lorc
                        14.07.2022 21:06

                        Как сказал? Какая сишная функция отвечает за взаимодействие с BIOS?

                        А какая сишная функция отвечает за обмен данными по сети? Или если в стандарте не описаны socket/ connect / send / recv то валидная сишная программа не может обмениваться данными через сокеты?

                        Я утверждаю, что нет.

                        Тем не менее, это будет валидный код:

                        An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

                        потому что pointer provenance.

                        Вообще, в стандарте C нет memory model. В отличии от стандарта C++.

                        И я утверждаю, что эту магию невозможно реализовать на стандартном C.

                        Таки можно. Это будет implementation-defined (еще бы, в windows вообще нет mmap), то стандарту это не противоречит.

                        Вообще, стандарт например упоминает такие штуки как memory-mapped input/output address или тот факт что hardware может изменять volatile переменные.


                      1. 0xd34df00d
                        14.07.2022 22:34

                        Или если в стандарте не описаны socket/ connect / send / recv то валидная сишная программа не может обмениваться данными через сокеты?

                        Ну, я бы сформулировал корректнее: невозможно на одном лишь стандартном С реализовать весь сетевой стек.


                        Тем не менее, это будет валидный код:

                        Нет, не будет.


                        An integer may be converted to any pointer type.

                        Я там его не только преобразую, но и разыменовываю.


                        Вообще, в стандарте C нет memory model. В отличии от стандарта C++.

                        Ну, я думаю, что с C11 таки есть, потому что в C11 тоже завезли многопоточность, а завозить её без memory model довольно тяжело.


                        Но это неважно: здесь речь идёт, во-первых, о лайфтаймах (6.2.4 в N1256, например).
                        Во-вторых, pointer provenance — это вообще какая-то наркомания, на которую у меня нет хорошего источника, и которую я вам предлагаю погуглить самостоятельно.


                        Это будет implementation-defined (еще бы, в windows вообще нет mmap), то стандарту это не противоречит.

                        Что именно? Куски магии? Нет, не будет implementation-defined.


                        Implementation-defined будет само наличие этой магии, но она действительно стоит за пределами стандарта.


                        Вообще, стандарт например упоминает такие штуки как memory-mapped input/output address или тот факт что hardware может изменять volatile переменные.

                        Да, единственное место — 6.7.3/5 и /6. Но эти пункты лишь описывают частные случаи undefined behaviour. У вас с ними не получится реализовать свой malloc или даже считать что-нибудь из биоса.


                        Из упоминания «UB даже неправильное по волатильности обращение к memory-mapped I/O address» не следует, что их можно иначе считывать.


                      1. lorc
                        14.07.2022 23:05

                        Ну, я бы сформулировал корректнее: невозможно на одном лишь стандартном С реализовать весь сетевой стек.

                        Почему? Стандарт даже прерывания упоминает. И memory IO вроде как не запрещает. Так что можно даже драйвер сетевой карты написать. Ну а дальше - пошло-поехало.

                        Я там его не только преобразую, но и разыменовываю.

                        Разыменовывать нельзя только невалидные указатели. Учитывая что валидность такого сконструированного указателя - implementation defined - то и правомерность его разыменования - тоже выходит implementation defined.

                        Короче да, это будет непереносимый код. Но стандартом явно не запрещенный же.

                        Ну, я думаю, что с C11 таки есть, потому что в C11 тоже завезли многопоточность, а завозить её без memory model довольно тяжело.

                        5.1.2.4 в N1548. Упоминается конфликт при доступе к memory location, а не к object. Объекты упоминаются только в контексте atomic object.

                        И, кстати, этот стандарт упоминает ‘‘volatile as device register’’ semantics. Что опять же намекает на возможность обращаться к железу прямо из сишной программы. Но вообще конечно могли бы написать прямо, что ли...

                        У вас с ними не получится реализовать свой malloc или даже считать что-нибудь из биоса.

                        Переносимым образом - да, очевидно не получится.

                        Из упоминания «UB даже неправильное по волатильности обращение к memory-mapped I/O address» не следует, что их можно иначе считывать.

                        Но и не следует что считывать их нельзя.

                        На этом невысказанном предположении и держится весь код операционных систем, гипервизоров, драйверов, прошивок и т.д... Кстати, стандарт явно описывает freestanding environment, т.е. возможность запускать программу без ОС.


                      1. 0xd34df00d
                        14.07.2022 23:33

                        Так, пажжите. Что для вас «стандартный C»? «Код, для которого существует хотя бы один соответствующий стандарту компилятор, который его сожрёт и сделает то, что я подразумеваю»? Или «Код, для которого любой соответствующий стандарту компилятор его сожрёт и сделает то, что я подразумеваю»?


                      1. lorc
                        14.07.2022 23:49

                        Ну так стандарт описывает оба случая. Они там называются conforming program и strictly conforming program соответственно.

                        Лично я выступаю за strictly conforming программы тогда, когда это возможно. Учитывая, что мы тут говорим все же про embedded и всякое такое, которое в принципе не может быть strictly conforming, остается довольствоваться просто conforming.


                      1. 0xd34df00d
                        14.07.2022 23:58
                        +1

                        Просто в такой формулировке и UB соответствует стандарту, а это не имеет смысла.


                      1. mpa4b
                        14.07.2022 17:20

                        mmap и sbrk подключают в адресное пространство процесса дополнительные mmu-странички с памятью. И всё. Как потом эту память нарезать на куски, выдаваемые в программу libc-шным malloc'ом или ещё каким аллокатором -- проблема исключительно этого malloc'а и прочего кода, выполняемого в юзерспейсе.


                      1. Stariy2003
                        15.07.2022 20:31

                        А вы сможете по машинному коду определить, на каком языке он написан? С++ от Асма отличите в ехе-шнике?


                      1. 0xd34df00d
                        15.07.2022 22:19

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


                        А вот месиво с замыканиями в ассемблере, получающемся из хаскеля, я прекрасно отличу от любого другого языка.


        1. Lazerate
          13.07.2022 22:49
          +15

          Вы, наверно, не в курсе, что запаривание алайнментом, аллокациями и т.д. ещё не значит, что это вообще как-то связано с Си. И то, что в С11, равно как и в С++11, вошёл тот же alignas, ещё не делает написание его или размышление над подобными вещами сишным.

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

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


          1. Chaos_Optima
            14.07.2022 05:47
            +3

            Под запариванием с выравниванием я подразумевал работу с теми самыми пресловутыми байтами, понятное дело что оно может быть сделано на более высоком уровне, тем не менее это всё тоже ковыряние с байтами, например DX константные буфера (да и все остальные ресурсы) мапятся в обычный кусок памяти и функция возвращает void* а дальше работай с этим куском памяти как заблагорассудится тут например и нужно запариваться с выравниванием. То что С++ имеет огромное количество инструментов для эффективного управления памятью не делает его менее С way это просто обёртка, которую без проблем можно заменить на свою.


            1. Lazerate
              14.07.2022 11:48
              +1

              Гм, ну, так любую работу с байтами на любом языке можно назвать абстракцикй над Си. А там и над ассемблером. Но банально вот до С++20 множество способов, которыми ковыряли и ковыряют байты в Си были попросту запрещены и приводили к неопределённому поведению. Ну а то, что всюду и везде Си апи это да. Но так, если докопаться, везде устроено – что-то в конечном итоге да будет дёргать код, написанный на Си. Это ведь всё ещё не значит, что любая работа с байтами в любом языке Си-way...


              1. Chaos_Optima
                14.07.2022 12:08

                Я не говорю про абстракции на Си я говорю что любое ковыряние с байтами, будь то выравнивание или мапинг, это С way даже если это ковыряние байтов в питоне или шарпах, потому что в данном случае необходимо знать что такое выравнивание и как всё в принципе работает на низком уровне. Просто в шарпах или том же питоне это практически никогда не встречается а в С++ постоянно, по крайней мере в моей сфере.


                1. eao197
                  14.07.2022 12:22

                  Я не говорю про абстракции на Си я говорю что любое ковыряние с байтами, будь то выравнивание или мапинг, это С way

                  Теперь бы еще понять почему.

                  Ковыряние байтов в Ada -- это тоже C way? А в Modula-2? А в Lisp, а в Algol-68?


                  1. Chaos_Optima
                    14.07.2022 12:58

                    В рамках данной статьи я считаю да, потому что идёт сравнение с С. Ясно дело что можно всё свести к тому что языки перебирающие байтики были и до С и по сути С way это ada way и так далее вплоть до Тьюринга.


                    1. eao197
                      14.07.2022 13:02

                      Смысла в ваших словах не видно. Но мысль я понял: если вам удобно называть операции с байтами "C way", значит вы будете называть это "C way" не смотря на то, что байтиками манипулировали и до Си, и после Си в языках, которые к Си никакого отношения не имели.

                      Удобно, чё.


          1. shybovycha
            14.07.2022 14:22
            +2

            Если я правильно понимаю, то арифметика на указателях это далеко от C++ way. И если мне не изменяет память, все те выразительные инструменты (в т.ч. для работы с памятью) которые предлагает С++ не особо хорошо натягиваются на некоторые задачи (программирование микроконтроллеров, например).

            То есть в моем понимании, если надо дикий перформанс и/или присутствуют жесткие ограничения по железу (ATtiny85 - 8KB flash, 512B RAM, 20MHz), то те же итераторы и умные указатели (насколько я помню, C++ Core Guidelines говорят о ручных выделениях и освобождениях памяти как о анти-паттерне) - не вариант. А иначе - это уже не каноничный С++.


            1. Kelbon Автор
              14.07.2022 14:31
              -3

              Итераторы это абстракция с отрицательной стоимостью, они не делают ваш код медленнее, наоборот ускоряет. unique_ptr только в некоторых случаях на некоторых платформах и АБИ будет иметь маленький оверхед. shared_ptr просто невозможен в С, замучаетесь.

              И да, указатели на умные, а владеющие. Это не замена T*


              1. PkXwmpgN
                14.07.2022 17:29

                unique_ptr только в некоторых случаях на некоторых платформах и АБИ будет иметь маленький оверхед

                https://youtu.be/rHIkrotSwcc?t=1058


            1. sim31r
              14.07.2022 19:55

              ATtiny85 даже среди микроконтроллеров 90х годов запредельный аскетизм, его можно на ассемблере программировать. Современные микроконтроллеры это типично STM32F4, 240МГц, мегабайты флеша, сотни килобайт памяти, он сравним с первыми Пентиумами по производительности.


              1. iamkisly
                15.07.2022 22:06

                Не согласен с самой концепцией которую вы вкладываете в "современные микроконтроллеры". У каждого производителя есть несколько линеек микроконтроллеров, каждая из которых имеет свое функциональное позиционирование, где она будет наиболее дешева и востребована. И из этой функциональной иерархии никуда не исчезли сверхдешевые 8-битники, или не производительные и емкие, но очень экономичные Cortex-M0/-M1.

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


        1. storoj
          13.07.2022 23:10

          деструктор в некоторой степени можно назвать примером декларативного программирования


        1. 0xd34df00d
          14.07.2022 05:29
          +5

          Я в трейдинге тоже парился над байтиками, выравниванием, аллокациями, и так далее, но делал это в очень плюсовом стиле.


          Кстати, а как функциональное программирование является императивным стилем? Какой смысл вы вообще вкладываете в эти слова?


          1. Chaos_Optima
            14.07.2022 05:56
            -2

            Кстати, а как функциональное программирование является императивным стилем? Какой смысл вы вообще вкладываете в эти слова?

            Что подразумевается под императивным стилем? Это последовательное выполнение инструкций и переиспользование результатов этих инструкций. Чем функциональное программирование в данном случае отличается, я имею ввиду реальные функциональные яп, в идеале функциональные языки являются декларативными, но по факту получается что мы всё также описываем последовательность инструкций которые должны последовательно выполнятся (я не беру в расчёт возможность перестановки или кеширования результатов компилятором\интерпретатором т.к. это есть и в С и в С++). Возможно моё понимание декларативного стиля не соответствует с обще принятым, но для меня всё это выглядит как просто вызов функций которые внешне декларативные но внутри всё тажа императивщина


            1. 0xd34df00d
              14.07.2022 06:27
              +3

              в идеале функциональные языки являются декларативными

              Ну вот хаскель — функциональный?


              Я там тоже могу написать набор байндингов, который как-то вычислится в нормальную форму и выведется мне на экран. При этом я, в принципе, могу более-менее рассуждать о порядке вычисления того, что получится, и делать это не сильно хуже, чем я рассуждаю о порядке выполнения операций в плюсовом коде (особенно с учётом того, что оптимизатор может некоторые вещи переупорядочивать и выкидывать). И, собственно, я не могу уловить принципиальную, качественную разницу стратегии вычисления.


              Разница между ленивым (вроде хаскеля) и энергичным (вроде идриса или хаскеля с -XStrict) функциональным языком тут будет сильно больше, чем разница между идрисом и плюсами.


            1. Kelbon Автор
              14.07.2022 07:02
              -3

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

              К тому же если взглянуть на QT или любую другую event based, ну или корутины С++20(или в целом асинхронное программирование), то там нет никакой последовательности, есть события и объекты


              1. Fell-x27
                14.07.2022 09:20
                +12

                Вы, похоже путаете императивность с "код движется строго сверху вниз", а декларативность с "код может перепрыгивать в функции/методы, которые, формально, выше исполняемого кода". Меня еще смутило, что вы признаком декларативности назвали goto...

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

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


                1. Kelbon Автор
                  14.07.2022 09:25

                  декларативность с "код может перепрыгивать в функции/методы, которые, формально, выше исполняемого кода". Меня еще смутило, что вы признаком декларативности назвали goto...

                  Откуда вы это взяли вообще? Я такого даже близко не говорил


                1. shybovycha
                  15.07.2022 00:59

                  Я так понял автор считает любую программу которая описывает последовательность действий для получения результата императивной. В таком случае декларативный только какой-нибудь Пролог (если я правильно понял автора).


        1. AllexIn
          14.07.2022 07:52
          +8

          Я в геймдеве как core программист работаю уже больше 15 лет.
          И полностью согласен с автором: при использовании С++ практически ничего из С не используется.
          При этом С я тоже знаю, писал для смарт часов софт на чистом С. И это адище то еще. Совершенно другой подход, сильно раздражающий.
          Но вернемся к геймдеву:
          Даже когда на плюсах пишеш низкоуровневую логику, всё равно придерживаешься С++ подходов. Даже условный аллокатор... Где там нужен С?
          Тем более современный геймдев, там вообще во всю шаблоны. И если 15 лет назад это воспринималось как "Эпики вообще больные, пишут движок на шаблонах. Это же будет тормозить!". То сейчас это "Эпики сделали стандарт индустрии".


          1. Chaos_Optima
            14.07.2022 13:06
            +1

            Очень интересно, можете рассказать как вы мапите те же Constant Buffers или заливаете ресурсы? А можно пример аллокатора без использования адресной арифметики? Конечно если вы используете готовые библиотеки или движки для этого, то вы и не столкнётесь с Си, но если пишете с нуля сишные ноги будут торчать из всех щелей.


            1. AllexIn
              14.07.2022 13:37
              +2

              С чего вдруг адресная арифметика стала С спецификой?
              Вы еще скажите, что использовать операцию сложения это С way, потому что сложение было в С.


              1. Chaos_Optima
                14.07.2022 14:07

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

                void* allocate(size_type size)
                {
                	void* out = hip_pos;
                    hip_pos = hip_pos + size;
                    return out;
                }

                Это код на С++ или на С? Я веду к тому что когда пишутся низкоуровневые вещи без использования дополнительных библиотек грань различия С и С++ практически стирается.


                1. eao197
                  14.07.2022 14:23

                  Разница обнаружится сразу же по выходу из allocate, т.к. в C++ вы не можете с void* обращаться так же вольно, как в Си. Начиная от того, что в C++ нет автоматического неявного каста из void* во что-то другое. И заканчивая тем, что нельзя просто так делать reinterpret_cast<T*>(some_void_p) (может потребоваться применять std::launder).


                  1. Chaos_Optima
                    14.07.2022 15:33
                    +1

                    Ну на выходе да, но речь то про внутренности. Взять тот же std::string снаружи всё красиво а внутри сишная карусель с указателями и байтами если есть sso


      1. mxr
        13.07.2022 21:20
        +6

        Как минимум kernel в том же CUDA Вы пишите именно на C.


        1. tabtre
          13.07.2022 23:34

          И на С++ можно
          К примеру из недавно встретившегося
          github.com/NVIDIA/nvcomp/blob/branch-2.2/src/RunLengthEncodeGPU.cu#L162


        1. Akon32
          14.07.2022 13:17
          +1

          CUDA ядра очень давно поддерживают фичи из С++, такие как классы, лет 10 минимум.


          1. mxr
            14.07.2022 13:28

            Там даже есть контейнеры, такие как vector для хоста и девайса. Но это все ещё С


            1. Akon32
              14.07.2022 15:12
              +1

              Что значит "это всё ещё С"? В 2011 году уже были С++ классы в device-коде, и С++ шаблоны. Это не С.


      1. RH215
        14.07.2022 15:01

        >А с точки зрения хорошего С++ кода практически ничего из С использовать не нужно

        ...но линуксовые API всё ещё написаны на C. Да и в целом, если необходимая тебе библиотека написана на С, то С рано или поздно в твоём cpp-коде окажется.

        Собственно, несмотря на то, что C и C++ - разные языки, у них есть общее подмножество, которое почти полностью совпадает с С.


      1. vconst
        15.07.2022 16:13

        Я помню оранжевую книжку, перевод Страуструпа
        image(без ката, пусть кто-то всплакнет)

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

        Систематизация — постоянно развивается. То, что раньше считалось отрядом — теперь считается подклассом. И наоборот. Можно продолжать хвататься за старое, но современные специалисты вам просто не поймут


    1. flx0
      13.07.2022 20:12
      +14

      Уже давно не подмножество. В плюсах нет как минимум restrict и _Generic (действительно, зачем он когда есть шаблоны?), да и код без них не всегда может быть скомпилирован обоими компиляторами из-за разных ограничений на приведение типов (тут я конкретный пример, впрочем, не вспомню).


      1. bakhtiyarov
        13.07.2022 21:49
        +4

        auto же! В C и в C++ это слово значит совсем разные вещи.


    1. Cheater
      13.07.2022 20:33
      +23

      C это подмножество C++

      Псст, хотите немного уличной магии!

      1) Преобразование int к enum

      enum { e0 = 0 } e = 0; // валидно в C, но не в C++

      2) Неявное преобразование void*

      void* pv = 0;

      int* pi = pv; // валидно в C, но не в C++


      1. QtRoS
        15.07.2022 10:02

        Да можно не выдумывать сложное, допустим вот так:

        int or;

        Скомпилируется в C, но не в C++


        1. Bokrenok
          15.07.2022 13:16

          "int class = 0;" забавнее


        1. sci_nov
          15.07.2022 22:20
          +1

          Фантазия, однако!


    1. iago
      13.07.2022 20:42
      +19

      Какое популярное заблуждение, я думал его уже давно нет. С - это подмножество Ojbc, которому я отдал 8 лет с 2009 по 2017 - это утверждение верно. Потому что код обжа сначала транслируется в чистый С, а потом компилится уже компилятором С. И в iOS до сих пор огромное множество фрэймворков написаны на чистом С.

      С++ же только внешне похож на С (и то был когда-то), под капотом совершенно другое. В их компиляторах ни одной общей строчки, один и тот же код компилится в совершенно другой АСМ.

      Про писать на C/C++ нет смысла расскажите разработчикам ОС и, например, игровых движков, им же расскажете и про тупые наборы байт.

      Я тоже обычный прикладной девелопер и пишу на swift, где днем с огнем не нужда адресная арифметика и системы реального времени. Но хоть нас и большинство, опрометчиво всех ровнять под одно.

      Как и автору оригинального поста - С++ до декларативности как Пугачеве до Мадонны, уж слишком он древний и громоздкий.


      1. Kelbon Автор
        13.07.2022 21:21
        -21

        Как и автору оригинального поста - С++ до декларативности как Пугачеве до Мадонны, уж слишком он древний и громоздкий.

        Может вы просто не умеете?)


        1. Chaos_Optima
          13.07.2022 22:07
          +17

          А может вы приведёте пример декларативного кода на С++?


          1. tzlom
            13.07.2022 22:39
            -2

            У меня есть маленькая библиотечка на C++11 которая из набора функций строит граф зависимостей (compile time) и выполняет его для заданных входов и результата/ов ,правда в публичном доступе её пока нет.


            1. Chaos_Optima
              14.07.2022 06:10

              Это всё использование библиотек, с таким же успехом можно написать библиотеки и на С которые позволят писать в декларативном стиле (да и вообще в любом), а на уровне языка есть что-то?


              1. Kelbon Автор
                14.07.2022 06:39
                -2

                Вот именно, что в С таких библиотек нет и быть не может. Даже теоретически.

                Реализуйте std:vector на С


                1. Chaos_Optima
                  14.07.2022 12:12

                  Ну что вам мешает написать на Си функцию на подобии этой?

                  struct IntArray arrr = zip(some_array, &zip_func);

                  Чем не декларативный стиль?


                  1. Kelbon Автор
                    14.07.2022 12:17
                    -1

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

                    Сравните производительность и интерфейс сишной сортировки и С++


                    1. Chaos_Optima
                      14.07.2022 13:17

                      А чем конкретно он мешает? Не скомпилится или что?

                      Сравните производительность и интерфейс сишной сортировки и С++

                      Сравнил  cpp.sh/43drd С++ получился быстрее. Только не понимаю к чему это?


          1. Kelbon Автор
            13.07.2022 22:45
            -8

            посмотрите на алгоритмы стл


            1. Chaos_Optima
              14.07.2022 06:07

              То есть для вас вызов готовых функций допустим из range уже является декларативным подходом, впринципе с если смотреть с этой стороны то любой язык может быть декларативным. Какие декларативные решения имеются на уровне синтаксиса языка? Интересно было бы увидеть.


              1. Kelbon Автор
                14.07.2022 06:43
                -4

                Эм, для вас использование готового языка программирования является декларативным подходом? Что за бред? Чем отличается "использование библиотеки" от использования языка в этом контексте?

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

                Вот вам из синтаксиса С++ декларативность : template, ... (pack expanding), range based for loop


                1. 0xd34df00d
                  14.07.2022 06:53
                  +6

                  Вот вам из синтаксиса С++ декларативность: template,… (pack expanding), range based for loop

                  Что из этого декларативно? template — это такой закос под параметрический полиморфизм с элементами паттерн-матчинга. range-based for loop — это практически целиком сахар поверх вызова begin и end. pack expansion — это вообще костыль для очень неудобной обработки списков параметров.


                  1. Kelbon Автор
                    14.07.2022 07:05
                    -8

                    Хаскель - это практически целиком сахар поверх вызова машинного кода. <Любая фича> такой вообще костыль для очень неудобного написания кода в С стиле


                    1. 0xd34df00d
                      14.07.2022 07:46
                      +2

                      Хаскель — это практически целиком сахар поверх вызова машинного кода.

                      В чём принципиальное отличие range-based for от BOOST_FOREACH/Q_FOREACH?


                      Но да, хаскель декларативным языком я бы не называл. Его прелесть не в этом.


          1. 0xd34df00d
            14.07.2022 05:38
            +3

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


            1. Chaos_Optima
              14.07.2022 06:20

              Ну полноценно декларативными языками можно назвать наверно html и sql всё остальное по мне выглядит императивным кодом, конечно можно сказать что вот например map это отношение данных и результата и это является декларативным стилем, но по мне это просто вызов готовой функции по сути инструкция.


              1. 0xd34df00d
                14.07.2022 06:30
                +2

                html не оч яп :]


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


                конечно можно сказать что вот например map это отношение данных и результата и это является декларативным стилем, но по мне это просто вызов готовой функции по сути инструкция.

                Именно, я тут с вами полностью согласен. И map ничем не отличается от плюсового std::transform, например.


                1. DabjeilQutwyngo
                  14.07.2022 09:50
                  -2

                  html не оч яп :]

                  hypertext markup language: программируется разметка, исполняется движком браузера как вычисление свойств всех элементов визуального представления. Просто потому что язык вообще -- это средство передачи информации, представленной значением выражения на этом языке. А как её интерпретирует получатель и что делает в связи с этим -- вопрос семантики и прагматики соответственно.

                  Людей вон тоже прекрасно программируют, используя естественный язык и механизм веры. Принцип его работы ничем не отличается от результата работы программатора: происходит подстановка программируемым объектом чего-либо на место значения выражения (в частности, термина или обозначения), которая не зависит от информационной связи с описываемым объектом.

                  Если со значением связать последовательность действий, у программируемого возникает некоторое поведение. И если записать в журнал последовательность действий, выполненных человеком за некоторый период времени в фиксированном контексте, получится программа этих действий, по определению. Потому что системные законы действуют неспецифично, а возникающее поведение не обязательно имеет программное описание, что никак не отменяет сказанное.


                  1. Ivanshka
                    14.07.2022 12:15
                    +3

                    программируется разметка

                    Разметка не программируется, а просто описывается. Именно потому HTML и не язык программирования, а язык разметки.


                    1. DabjeilQutwyngo
                      14.07.2022 22:18

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


                      1. 0xd34df00d
                        14.07.2022 22:35

                        Можно пример чего-нибудь, что не является программой?


                  1. 0xd34df00d
                    14.07.2022 16:29
                    +3

                    hypertext markup language: программируется разметка, исполняется движком браузера как вычисление свойств всех элементов визуального представления

                    Там нет программирования в классическом околотьюринговом смысле.


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

                    На хабре объявили неделю игр с многозначными терминами, что ли? Позавчера вон в соседнем треде товарищ всё находил диалектические противоречия в том, что переменные — переменные, теперь у вас программирование людей почему-то идёт следом за языком программирования html.


                    1. DabjeilQutwyngo
                      14.07.2022 22:29

                      То, что вы исключили что-либо из объёма понятия "программа", и, как следствие, "программирование", извменив тем самым содержание понятия (т.к. для вашего понятия требуется иное характеристическое свойство), и в результате термин стал для вас многозначный, не означает, что термин многозначный: это вы его так понимаете, проводя ложное разделение, как минимум. См. выше объяснение такому же товарищу.

                      Ваша общая ошибка в том, что считаете программой лишь то, что выражено в императивном стиле. Если выразить в командах рисования графических объектов то, что показывается на экране в результате рендеринга html-кода, то получится именно то, что вы называете программой. Хотя программа -- это предписание исполняющему устройству. А программирование -- это формирование такого предписания.

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


                      1. 0xd34df00d
                        14.07.2022 22:36
                        +1

                        Очень хорошо. Является ли картинка программой?


                      1. Cerberuser
                        15.07.2022 05:21
                        +1

                        https://esolangs.org/wiki/Piet (либо его аналог, если нужно что-то, к примеру, с большим количеством цветов)? That is, она может не являться программой сама по себе, но она может быть интерпретирована как таковая (а без способа интерпретации и код на C, и bare-metal бинарник тоже программами являться не будут).


                      1. 0xd34df00d
                        15.07.2022 17:42

                        В принципе, так-то и последовательность камешков, которыми выстлана дорожка к двери в мой дом, является программой.


                      1. arTk_ev
                        15.07.2022 12:34

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

                        Машина состояний не является тьюринг полной, поэтому не является полноценной программой.

                        Для функционального и асинхронного программирования, программа - это уже не набор инструкций, но все равно тьюринг полное.


                      1. 0xd34df00d
                        15.07.2022 17:44

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


            1. pfffffffffffff
              14.07.2022 08:08
              +1

              Пролог как раз декларативно логический язык. Что выглядит декларативно так это описание интерфейса в vuejs.


            1. DabjeilQutwyngo
              14.07.2022 09:58
              -1

              что такое декларативный подход

              boost::xpressive::sregex, например.


              1. Jian
                14.07.2022 10:47

                что такое декларативный подход

                boost::xpressive::sregex, например.

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


                1. DabjeilQutwyngo
                  14.07.2022 21:21

                  То, что нечто реализовано посредством ООП, не означает, что на уровне использования не декларативный подход. А он декларативный: описывается выражение на sregex (производный специализированный доменный язык (Domain Specific Language) от PerlRe и синтаксиса C++), но при этом никаких шагов по его выполнению не предписывается. Пример:

                  sregex re_year = bos >> repeat<4,4>(_d) >> eos;

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


              1. 0xd34df00d
                14.07.2022 16:31
                +2

                А что там декларативного?


                Является ли, к слову о регулярках, декларативным это? На мой взгляд — нет.


                1. DabjeilQutwyngo
                  14.07.2022 21:23

                  По определению проверять нужно, а не по взгляду. В регулярном выражении никаких шагов по его выполнению не предписывается. А шагами выполнения, напомню, является выполнение переходов конечным автоматом, проверяющим принадлежность заданной цепочки регулярному языку, заданному регулярным выражением. Пример выше.


                  1. 0xd34df00d
                    14.07.2022 22:36

                    А, то есть, декларативна не библиотека, а сами регулярки, включая какой-нибудь std::regex и вполне себе сишный PCRE?


          1. eao197
            14.07.2022 07:43
            +3

            Пожалуй, не буду скромным и приведу пример из своей же статьи двухлетней давности:

            auto make_parser()
            {
               auto token_to_v = []( std::string v ) -> param_value_t {
                  return { std::move(v), value_form_t::token };
               };
               auto qstring_to_v = []( std::string v ) -> param_value_t {
                  return { std::move(v), value_form_t::quoted_string };
               };
            
               auto token68_seq = sequence(
                     token68_p() >> as_result(),
                     not_clause( any_symbol_p() >> skip() ) );
            
               // Список параметров вида name=value может быть пустым.
               auto params_seq = maybe_empty_comma_separated_list_p< param_container_t >(
                     produce< param_t >(
                        token_p() >> to_lower() >> &param_t::name,
                        ows(),
                        symbol('='),
                        ows(),
                        produce< param_value_t >(
                           alternatives(
                              token_p() >> convert( token_to_v ) >> as_result(),
                              quoted_string_p() >> convert( qstring_to_v )
                                    >> as_result()
                           )
                        ) >> &param_t::value
                     )
                  ) >> as_result();
            
               return produce< authorization_value_t >(
                     token_p() >> to_lower() >> &authorization_value_t::auth_scheme,
                     maybe(
                        repeat( 1, N, space() ),
                        produce< auth_param_t >(
                              alternatives( token68_seq, params_seq )
                        ) >> &authorization_value_t::auth_param
                     )
               );
            }

            Код не для статьи написан, он реально живет в нашей библиотеке.


            1. Chaos_Optima
              14.07.2022 12:33
              +1

              Это функциональный подход, только причём тут декларативность? Тут ясень порядок выполнения инструкций, он чётко определён вами. Если бы написали что-нибудь в духе

              auto value = group | 
                select| {value_form_t::token, value_form_t::quoted_string} |
                from | some_string;

              И компилятор бы сам решал в каком порядке всё выполнять и как разбивать это можно было бы назвать декларативным программированием.


              1. Kelbon Автор
                14.07.2022 12:37

                так он и решает ...


              1. eao197
                14.07.2022 12:40
                -2

                Это функциональный подход, только причём тут декларативность?

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

                Тут ясень порядок выполнения инструкций, он чётко определён вами.

                Он определен не мной, а грамматикой. Или, по вашему мнению, EBNF нотации не декларативны?


                1. 0xd34df00d
                  14.07.2022 16:33

                  По (e)BNF можно чисто синтаксически построить императивный парсер.


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


                  1. eao197
                    14.07.2022 16:40

                    По (e)BNF можно чисто синтаксически построить императивный парсер.

                    Само описание EBNF что-то говорит о том, какой это будет парсер: нисходящий или восходящий?


                    1. 0xd34df00d
                      14.07.2022 16:45

                      Для некоторого класса языков это неважно, для другого класса языков только восходящий (ЕМНИП, я-то обычно вообще PEG'и пишу, и мне пофиг) сработает.


                      1. eao197
                        14.07.2022 16:54

                        А могли бы вы упражняться в софистике самостоятельно?


                      1. 0xd34df00d
                        14.07.2022 16:55

                        Не понял, где тут софистика, ну да ладно.


                  1. DabjeilQutwyngo
                    14.07.2022 21:59

                    Ну так парсер и язык -- не одно и тоже: это разные уровни и разные системы. Более того, парсера мало: для получения поведения требуется интерпретатор, как минимум. Путаете уровень интерфейса с уровнем реализации опять.

                    Парсер можно реализовывать кустарно ("что вижу, то пою") -- в императивном стиле. Т.е. выражать обработку комбинаций элементов языка, встретившихся в анализируемой цепочке, процедурно, непосредственно заданными шагами. А можно через построение отображения на основе грамматики языка и таблицы трансляции ситуаций, определённых комбинациями правил грамматики языка, в требуемое (символы и цепочки другого языка).

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

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

                    Даже банальная последовательность цифр числа в арабской записи -- не что иное, как краткая запись суммы чисел, обозначенных цифрами, умноженными на степень основания выбранной системы счисления. Показатель этой степени поставлен в однооднозначное соответствие порядковому номеру разряда числа (нумеровать можно с разным смещением и направлением). Эта сумма считается неприводимой к более компактной в рамках выбранного языка.

                    Сложность и методы таблицы трансляции не ограничиваются. Фактически, всё время имеем дело с синтаксически управляемым переводом. И в какой-то момент символами и терминалами становятся действия исполняющего устройства. Т.е. язык -- это средство описания варианта поведения исполняющего устройства. Понятия декларативности и императивности применяются к языку и выражениям на нём, а не исполняющему устройству.

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


                    1. 0xd34df00d
                      14.07.2022 22:44

                      Ну так парсер и язык — не одно и тоже: это разные уровни и разные системы. Более того, парсера мало: для получения поведения требуется интерпретатор, как минимум.

                      Формальные языки в информатике — это именно что чистый синтаксис, без какого-либо поведения, интерпретатора и так далее.


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


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

                      Это императивный стиль?


                      А можно через построение отображения на основе грамматики языка и таблицы трансляции ситуаций, определённых комбинациями правил грамматики языка, в требуемое (символы и цепочки другого языка).

                      Вы ведь знаете, что таблицы трансляций [конечного числа] состояний недостаточно для существенных классов языков? Ну там, фундаментальное образование в ИТ, все дела?


          1. antonkrechetov
            14.07.2022 21:43

            А может вы приведёте пример декларативного кода на С++?
            Я попробую. Вот код для вычисления N-го числа Фибоначчи на этапе компиляции:
            typedef unsigned long int num;
            
            template <num N> class fib {
              public:
                static const num value = fib<N-1>::value + fib<N-2>::value;
            };
            
            template <> class fib<0> {
              public:
                static const num value = 1;
            };
            
            template <> class fib<1> {
              public:
                static const num value = 1;
            };
            По-моему, вполне декларативно) Конечно, для вывода результата понадобится императивный код, например std::cout << fib<6>::value (выведет 13).

            Если что, я не настоящий С++-разработчик, так что качество кода может хромать и т.д.


      1. funca
        13.07.2022 22:11
        +3

        Потому что код обжа сначала транслируется в чистый С, а потом компилится уже компилятором С

        Многие языки умеют транслироваться в С. В этом случае С выполняет роль этакого макроассемблера - компиляторы С есть практически под любую платформу и не надо мудрить со своим. Так что наличие этой фичи самой по себе вовсе не аргумент, чтобы считать одно подмножеством другого.


      1. domix32
        13.07.2022 22:35
        +6

        В их компиляторах ни одной общей строчки

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


        1. kin4stat
          15.07.2022 09:52
          +1

          Фронтенд LLVM, например, у обоих будет разных. Но Middleend и Backend одинаковый. Ни одной строчки это конечно очень сильно было сказано


    1. Icon0clast
      13.07.2022 22:24
      +10

      C не есть подмножество C++ как минимум из-за: restrict указателей, _Generic макросов и _Noreturn функций. Кроме этого, описанный вами миф развенчивал ещё Страуструп в своей книжке, почитайте его на досуге.


    1. F0iL
      13.07.2022 22:55

      Из того что обсуждали недавно тут, в копилку о том, почему C не есть подмножество C++: в Си type-puning через union'ы вполне допустим и повсеместно используется, в C++ же он является нарушением стандарта.


    1. Nick_Shl
      14.07.2022 04:42

      C это подмножество C++

      Нет! Наоборот: С++ это "надстройка" над С.


      1. IKStantin
        14.07.2022 14:24
        +1

        Когда я работал преподавателем программирования на УПК в 1992 году, именно так мы и преподносили.

        C++ - расширение языка C для работы с классами. И ООП мы изучали на библиотеке Turbo Vision. Была такая в Borland C++ для работы с псевдографическими окнами в текстовом режиме DOS.


      1. Jian
        14.07.2022 14:28
        +1

        С++ это "надстройка" над С

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


    1. agalakhov
      14.07.2022 21:27

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


      1. QtRoS
        15.07.2022 12:20

        Давно уже можно такое написать, смотрите мой комментарий. Минимум начиная с 98 стандарта.

        "or" is an inbuilt keyword that has been around since at least C++98


    1. tsilia
      15.07.2022 09:49

      Что-то никто в этой ветке не упоминает VLA как одну из фич C, которых нет в C++. Или его уже в стандарт плюсов завезли? Когда чекал это последний раз, g++ поддерживал его только как расширение стандарта C++.


  1. Racheengel
    13.07.2022 20:36
    +27

    Обычно поиск программиста на С/С++ значит, что на фирме есть и код на С, и код на С++, а скорее всего даже внутри одного продукта. И бедняге придётся окунаться в оба болота сразу.


    1. staticmain
      13.07.2022 21:43
      +18

      Или когда весь код на С++, но писали его программисты на С с malloc, free, функциями из cstd хедеров.


    1. PkXwmpgN
      13.07.2022 22:42
      +8

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


  1. victor_1212
    13.07.2022 20:46
    +15

    > И это не абстрактные рассуждения в вакууме

    просто любопытно, что такого автор сделал в программировании чтобы выражаться в стиле "тупыми наборами байт", " глубокий наколеночный эмбед", " языки требуют абсолютно разных умений и подходов к разработке", оба использовал практически с момента появления первых компиляторов, (30+ лет), ничего особенного в С++ vs С не вижу, просто tool, для одних проектов лучше С, для других больше подходит С++, не более того


    1. 0xd34df00d
      14.07.2022 05:40
      +6

      Спердоб — это, если честно, так себе аргумент. Особенно когда в роли контр-спердоба выступает «да я 30 лет пишу».


      1. victor_1212
        14.07.2022 20:14
        +1

        Вы не совсем поняли, предмета спора "кто больше знает" нет, вопрос к терминологии автора, профессионалы так не пишут, даже если он эксперт и сидел в офисе рядом с Страуструпом, остальное слегка Ваши фантазии


        1. 0xd34df00d
          14.07.2022 22:45

          Вы не совсем поняли, предмета спора "кто больше знает" нет, вопрос к терминологии автора, профессионалы так не пишут

          Профессионалы как только не пишут. Не надо так сильно молиться на серьёзность.


          даже если он эксперт и сидел в офисе рядом с Страуструпом

          Сомнительный критерий экспертности, ну да ладно.


          остальное слегка Ваши фантазии

          Формулировка


          оба использовал практически с момента появления первых компиляторов, (30+ лет) [...]

          не оставляет особого простора для фантазий.


          1. victor_1212
            14.07.2022 23:59

            тем не менее нашли "спердоб", какие у Вас вопросы к "30+ лет"?

            если нет, предлагаю закончить, не в возрасте дело, адреналина от демонстрации технических знаний не получал никогда, в том числе когда было столько лет, сколько Вам сейчас, типа более интересные занятия были


            1. 0xd34df00d
              15.07.2022 17:46

              Я иначе не очень понимаю, к чему там эти 30+ лет были, только и всего. Ровно ту же мысль, которую вы написали, можно передать и без упоминания личного опыта в 30+ лет.


              Но, впрочем, не имели в виду спердоб — ну и славно.


              в том числе когда было столько лет, сколько Вам сейчас

              :]


              1. victor_1212
                15.07.2022 21:24

                нет проблем, " 30+" в общем случайно, приходится задумываться иногда, может поймете когда-нибудь :)


        1. Koval97
          15.07.2022 13:04
          -2

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


          1. victor_1212
            15.07.2022 14:54

            примерно понимаю, лопата придумана чтобы траншеи копать и каналы строить, конечно документацию на лопату тоже надо знать, включая стандарт как reference, и особенности компилятора, imho особенно гордиться здесь не чем, в конце концов стандарт люди создали, и компилятор как правило кто-то другой написал, типа чужая работа, лучше что-нибудь свое как следует сделать, пусть даже чужой лопатой :)


            1. victor_1212
              15.07.2022 16:28

              вероятно наступил кому-нибудь на лапу :)

              через 20 мин это сообщение принесло -1 в карму, без разницы конечно, посмотрим что дальше будет


  1. Magister-Ice
    13.07.2022 20:51
    +1

    Исходя из изложенного материала, например, программа написанная на чистом C с использованием API DirectX, является C или C++ программой?


    1. Chaos_Optima
      13.07.2022 21:25
      +1

      А как ты на С напишешь с использованием DirectX там же ооп апи, или я что-то упустил.


      1. Magister-Ice
        13.07.2022 21:35
        +1

        Да, получится гибридное решение, C код с созданием и использоваине объектов из API. ИМХО в итоге получится некий гибрид C/C++, котрый не C, не C++, вполне жизнеспособен и ничему не противоречит.


      1. tangro
        13.07.2022 22:17
        +5

        Чтоб Вы были в курсе: DirectX имеет два набора API: для С и для С++. Это вот прямо разные заголовочные файлы или отделённые через ifdef секции в одном заголовочном файле. DirectX изначально разрабатывался как высокопродуктивная графическая подсистема и её, конечно, нельзя было намертво прикрутить к одному лишь С++ и забыть С.


        1. Chaos_Optima
          14.07.2022 06:11
          +1

          Да действительно посмотрел щас d3d12.h и правда, был не прав С api присутствует


        1. shybovycha
          15.07.2022 01:24

          Всегда как смотрел на DirectX воспринимал его как такой сильный C way - когда объявляется дескриптор, который struct с десятком полей, а потом на нем вызывается функция (даже если как метод класса). В моем понимании C++ way это ООП, потому я ожидал бы какой-нибудь builder (как шаблон проектирования). Но это все философия, я так понимаю это либо пережиток прошлого, либо решение в пользу производительности. Вроде тот же Vulkan имеет точно такой же подход, так что скорее второе.


  1. r6l-025
    13.07.2022 21:01
    +7

    Я подозреваю что когда пишет не C++, а C/C++ - то хотят видеть человека умеющего работать с обоими парадигмами. Хотя, иногда попадаются очень забавные объявление от HR котрые их не всегда различают: " Хотим знание Си и boost". А вот на счет наколеночного embedded я бы поспорил (иначе Linux kernel, Postgresqsl, etc. превращаются в наколеночный embedded)


    1. Kelbon Автор
      13.07.2022 21:01
      -21

      У линукса нет объективных причин не использовать С++. Но есть Линус, который по личным каким то предпочтениям не хочет


      1. lorc
        13.07.2022 22:56
        +17

        А какой профит принесет C++ ядру линукса? Появится 11 разных способов инициализировать поле класса? Как там со стабильным ABI? В ядре периодически то ассемблерный код дергает сишные функции, то сишный код дергает ассемблер. И модули загружаются/выгружаются прямо в рантайме.

        А если вы расскажете как делать всякие более продвинутые штуки типа динамической трассировки C++ кода (как ftrace и kprobe в ядре) - будет вообще круто.


        1. Kelbon Автор
          14.07.2022 07:12
          +1

          Появится 11 разных способов инициализировать поле класса?

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

          Как там со стабильным ABI

          Как-то коммитету по стандартизации С++ получается держать стабильное ABI, про extern "C" промолчу

           И модули загружаются/выгружаются прямо в рантайме.

          и чё? Как это мешает то?

          А если вы расскажете как делать всякие более продвинутые штуки типа динамической трассировки C++ кода (как ftrace и kprobe в ядре) - будет вообще круто.

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

          Ну или как прочитать строку, пришедшую в мейн с неизвестным размером


          1. Cerberuser
            14.07.2022 08:18
            +1

            Появится способ создавать классы.

            Но зачем? Какую задачу это будет решать с точки зрения ядра? А то фраза звучит так, как будто наличие такой задачи заведомо очевидно.


            1. Kelbon Автор
              14.07.2022 08:32

              Если там на языке С эмулируют это, то очевидно потребность есть


              1. mikhanoid
                14.07.2022 10:19
                +16

                Там не классы эмулируют, а интерфейсы. А для этого C++ - overkill. C++ сложный язык, создающий зависимость от разработчиков компиляторов для C++, от комитета стандартизации C++ и от многолетней учёбы, необходимой для освоения C++ и от прочих слциальных институтов. Linux, он, как бы, не про это, а про индивидуальную свободу и независимость. Сносный компилятор C можно написать с нуля в одиночку за приемлемое время и раскрутить на этом компиляторе GNU/Linux. Написание компилятора C++ современного стандарта - это отдельное приключение длинною в десятилетие.


                1. mikhanoid
                  14.07.2022 11:33

                  p.s. прошу прощения за грамматические ошибки


                1. F0iL
                  14.07.2022 12:15
                  +3

                  Сносный компилятор C можно написать с нуля в одиночку за приемлемое время и раскрутить на этом компиляторе GNU/Linux.

                  Ага, ага. Достаточно вспомнить, что спустя три года активной разработки Clang все еще не мог полностью собрать линуксовое ядро, и даже спустя еще 7 лет после этого ядро нормально собиралось им только со специальными патчами. TCC может собирать только очень древние версии ядра (2.4.x), и даже навороченный интеловский ICC собирал ядро тоже только при наложении специальных патчей, а сейчас они вообще на это дело забили.


                  1. lorc
                    14.07.2022 12:52
                    +1

                    Некорректный пример, потому что линуксовое ядро прямо заточено под сборку на GCC. Там используется куча gcc-шних расширений где только можно. Вообще, говорить что ядро линукса написано на C - не совсем верно.

                    В то же время есть приложения которые собираются хоть gcc, хоть icc, хоть Keil C.


                    1. F0iL
                      14.07.2022 15:24
                      +3

                      Что значит "некорректный пример"? Перечитайте исходный комментарий выше, там человек говорил именно про компиляцию линуксового ядра, поэтому я и отвечаю про компиляцию линуксового ядра.


              1. Gordon01
                14.07.2022 13:29

                Там только создают объекты из структур, без наследования и прочей ООП чепухи.

                На си это нормально получается, хотя в каком-нибудь расте еще красивее.


          1. r6l-025
            14.07.2022 10:11
            +1

            А чем вам не понравились классы в ядре? Их там не много, и они весьма в удачных местах. Например, класс с файловыми операциями. А на счет производительности... нужны бенчмарки. Как-то интуитивно выглядит как раз наоборот. В Си это просто разыменование указателей для вызова функций. А в плюсах?


            1. Kelbon Автор
              14.07.2022 10:20
              -3

              интуитивно создавать все объекты на куче потому что язык не позволяет сделать это на стеке это не эффективно. И разыменовывать каждый раз указатель чтобы пойти к значению это тоже неэффективно. Зачем вообще рассуждать об эффективности, если вы не понимаете как методы в плюсах вызываются?


              1. lorc
                14.07.2022 10:53
                +4

                интуитивно создавать все объекты на куче потому что язык не позволяет сделать это на стеке это не эффективно.

                В каком месте C не позволяет создавать объекты на стеке? О чем вы вообще? К тому же, у всех линуксовых объектов очень длинное время жизни, их нет смысла создавать на стеке.

                И разыменовывать каждый раз указатель чтобы пойти к значению это тоже неэффективно

                А как вы собираетесь вызывать виртуальные методы? В C++ точно то же самое - полезли в vtable, нашли указатель на метод.

                Зачем вообще рассуждать об эффективности, если вы не понимаете как методы в плюсах вызываются?

                О, а вы можете рассказать как вызываются методы в плюсах? Вот например я хочу вызвать C++ метод из ассемблерного кода. Как мне это сделать? (вопрос с подвохом, да).


                1. Kelbon Автор
                  14.07.2022 10:59
                  -3

                  В С эмулируют инкапсуляцию используя pimpl повсеместно, что не даёт возможности создавать на стеке. И там же образуется лишний дереференс при доступе к объекту

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

                  Из ассемблера вызывайте че хотите как хотите, мне это не нужно


                  1. lorc
                    14.07.2022 11:02
                    +3

                    В С эмулируют инкапсуляцию используя pimpl повсеместно, что не даёт возможности создавать на стеке.

                    Почему? Я не могу создать структуру на стеке? Или о чем вы?

                    Из ассемблера вызывайте че хотите как хотите, мне это не нужно

                    Ядру линукса это нужно. Мы же тут говорим о том, что линукс мог бы быть написать на C++, не так ли? Вот ваши слова:

                    У линукса нет объективных причин не использовать С++.

                    Раз уж нет объективных причин не использовать, то расскажите про interop с ассемблером.


                    1. Kelbon Автор
                      14.07.2022 11:06
                      -6

                      Почему? Я не могу создать структуру на стеке? Или о чем вы?

                      Когда нибудь вы поймёте

                       Мы же тут говорим о том, что линукс мог бы быть написать на C++, не так ли? Вот ваши слова:

                      Где я это сказал? Откуда вы это взяли вообще? Мои слова, это то что у Линуса Торвальдса нет никаких реальных оснований не допускать С++ в линукс.


                      1. lorc
                        14.07.2022 11:17
                        +2

                        Когда нибудь вы поймёте

                        Это не ответ, а риторический прием. При чем - плохой риторический прием. Расскажите мне что именно C не позволяет создавать на стеке и чем это плохо. Или покажите где почитать об этом.

                        Мои слова, это то что у Линуса Торвальдса нет никаких реальных оснований не допускать С++ в линукс.

                        Может все таки есть? Вот например - отсутствие стандартного ABI и проблемы взаимодействия с низкоуровневым кодом из-за этого.


                      1. eao197
                        14.07.2022 12:08
                        +1

                        Давайте возьмем простенький пример: https://wandbox.org/permlink/SCa50brKPVZfghMF

                        Интересно посмотреть на объем кода на чистом Си, который бы делал бы тоже самое.


                      1. lorc
                        14.07.2022 12:38
                        +1

                        Да легко: https://wandbox.org/permlink/wKY1HxU9zj1G1cHY

                        Сильно объем кода отличается?


                      1. eao197
                        14.07.2022 12:41
                        +1

                        Не зачет. name -- это метод.


                      1. lorc
                        14.07.2022 12:47

                        Я рад за него. Только это ж банальный геттер который возвращает константу. Не проще тогда хранить сразу константу? Ах да, наследование в C++ не позволяет переопределять значения полей... Поэтому вариант C получился быстрее даже - минус один вызов функции/метода.

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


                      1. eao197
                        14.07.2022 12:52
                        +1

                        Только это ж банальный геттер который возвращает константу. 

                        Кто вам сказал? Метод в базовом классе объявлен как виртуальный.

                        Ах да, наследование в C++ не позволяет переопределять значения полей...

                        Это вы сейчас о чем?

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

                        Этот примитивнейший пример показывать насколько хрупким будет аналог на чистом Си, в котором все гарантии на уровне "мамой клянусь".

                        Да и тот повторить не смогли 1-в-1.


                      1. lorc
                        14.07.2022 13:07

                        Кто вам сказал? Метод в базовом классе объявлен как виртуальный.

                        Ну по факту он возвращает константную строку. Ведет себя как классический геттер (без сеттера, да).

                        Это вы сейчас о чем?

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

                        Да и тот повторить не смогли 1-в-1.

                        А была цель повторить 1:1? Вы просили код

                        который бы делал бы тоже самое.

                        Я привел код который делает то же самое. Предоставляет интерфейс Animal который позволяет узнать имя конкретного класса и вызвать метод.


                      1. eao197
                        14.07.2022 13:15

                        Ну по факту он возвращает константную строку.

                        Если уж говорить про факты, то

                        a) возвращается динамическая строка;

                        b) функция use_animal завязана на то, чтобы вызывать name у наследников и этот name может иметь разные реализации.

                        Ничего подобного у вас в коде нет. Хотя докапываться до `const char*` вместо std::string у меня желания и не было. Хотелось просто увидеть в коде ручное проставление нескольких указателей на "виртуальные" методы, но это оказалось слишкамсложна.

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

                        Давайте еще раз и так, чтобы было понятно не только вам. А то складывается впечатление, что C++ вы и не знаете.

                        А была цель повторить 1:1? Вы просили код

                        Который бы делал тоже самое. Тоже самое. А не то, что вам оказалось проще.

                        Я привел код который делает то же самое.

                        Нет.


                      1. Kelbon Автор
                        14.07.2022 13:17
                        -1

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


                      1. eao197
                        14.07.2022 13:18

                        Давайте не будем грести всех Сишников под одну гребенку.


                      1. lorc
                        14.07.2022 13:19

                        Который бы делал тоже самое. Тоже самое. А не то, что вам оказалось проще.

                        Очевидно, что если взять язык B и попросить сделать на нем "точно то же самое" что было сделано на языке А, то получится дикая каша. Потому что это разные языки.

                        Я утверждаю что моя программа семантически эквивалентна вашей.

                        Нет.

                        Okay...


                      1. Kelbon Автор
                        14.07.2022 13:21
                        -1

                        Почему то на С++ можно сделать то же самое что на С, а вот на С то же самое что на С++ не получается, интересно...


                      1. lorc
                        14.07.2022 13:29
                        +2

                        Сделайте мне на C++ per_cpu переменную как в ядре линукса. И нет, это не thread local storage, это именно per CPU.


                      1. eao197
                        14.07.2022 13:22

                        Я утверждаю что моя программа семантически эквивалентна вашей.

                        Вот только элементарных проверок ваше утверждение не проходит.


                      1. lorc
                        14.07.2022 13:31

                        Нужно было точнее ставить задачу. Или хотя бы привести список "проверок".
                        Не все обладают телепатией.


                      1. eao197
                        14.07.2022 13:50

                        Для знающего C++ там все очевидно:

                        • есть интерфейс;

                        • в этом интерфейсе есть две виртуальные функции. Причем виртуальную функцию action нельзя применять к константному объекту (указателю/ссылке);

                        • оба эти функции являются чистыми виртуальными. Т.е. компилятор не даст нам создать экземпляр типа, в котором не реализована хотя бы одна из них;

                        • есть функция use_animal, которая завязана на этот интерфейс;

                        • есть два наследника, которые реализуют этот интерфейс;

                        • наследники создаются на стеке, но передаются в use_animal, при этом use_animal ничего не знает о наследниках.

                        Я тут даже не буду заострять внимание на то, что name возвращает созданную в динамической памяти строку. И на то, что наследников Animal можно безопасно удалять по указателю на сам Animal. Т.к. к вопросу о создании экземпляров на стеке это не имеет отношения.


                      1. eao197
                        14.07.2022 13:20

                        Я привел код который делает то же самое

                        Еще одно важное отличие забыл вписать: у вас нет отдельных типов для Cat и Dog. Т.е. мой пример можно расширить условной функцией:

                        void walk_dog(const Dog & d);

                        И в эту функцию нельзя будет просто так передать Cat. А у вас вообще понятия Dog нет.


                      1. Kelbon Автор
                        14.07.2022 13:07

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

                        Вы изменили логику, а не "сделали быстрее", бенчмарки должны быть идентичными.
                        Но вы лучше вот это прокомментируйте, как вы сделаете лучше на С(никак)

                        https://godbolt.org/z/PMMeGMevT


                      1. 0xd34df00d
                        14.07.2022 16:43

                        Только это ж банальный геттер который возвращает константу. Не проще тогда хранить сразу константу?

                        Одна из характеристик интеллекта — это способность разрешать неоднозначности и понимать абстракции.


                        Если так уж хотите, то рассмотрите такой пример: https://wandbox.org/permlink/Wuz2ahyHUGXb1V74


                        Ах да, наследование в C++ не позволяет переопределять значения полей...

                        Не понял.


                        struct Base
                        {
                          int theAnswer = 42;
                        };
                        
                        struct Derived : Base
                        {
                          Derived()
                          {
                              theAnswer = 6;
                          }
                        };


                      1. lorc
                        14.07.2022 17:07

                        Одна из характеристик интеллекта — это способность разрешать неоднозначности и понимать абстракции. Если так уж хотите, то рассмотрите такой пример: https://wandbox.org/permlink/Wuz2ahyHUGXb1V74

                        Хех. Ну окей. Я могу завести отдельную структуру animal_ops и держать там поинтеры на разные функции. Будет совсем такой vtable как хотел ОП.

                        Ну и да, очевидно что это не так безопасно по типам как было в C++.

                        Не понял.

                        О, вот сразу бы так :)


                      1. Kelbon Автор
                        14.07.2022 12:46
                        -1

                        У вас vtable неправильная, переделывайте. Во первых метода не 3 а 1, во вторых не указатель хранится, а сам vtable, ваш код значительно менее эффективен.


                      1. lorc
                        14.07.2022 13:00

                        А мы тут собрались копировать плюсовую имплементацию 1:1 или повторить семантику? Семантика интерфейса повторена, а то что оно ведет себя не как код на C++ - так это и понятно. Оно ж написано не на C++.

                        Я могу повторить тот же код на Python например. Там вы тоже будете предъявлять претензии к тому что vtable не такой?


                      1. Kelbon Автор
                        14.07.2022 13:02

                        А теперь задачка вам действительно сложная, попробуйте реализовать эффективнее чем понятный и логичный, короткий код на С++, но с использованием другого вида динамического полиморфизма. Там нет никаких виртуальных таблиц внутри типов, они гораздо лучше расположены. И выделений памяти нет.

                        И эффективнее, понятнее и короче код чем в С

                        https://godbolt.org/z/6zc5Ync3x

                        Спойлер - не получится у вас


                      1. lorc
                        14.07.2022 13:15

                        И эффективнее, понятнее и короче код чем в С

                        Ну если вот это: https://raw.githubusercontent.com/kelbon/AnyAny/main/include/anyany.hpp

                        "Эффективнее и короче" чем мой код на C, то я даже не знаю...


                      1. Kelbon Автор
                        14.07.2022 13:18
                        -1

                        Ну тогда линуксом не пользуйтесь, там небось тоже много кода

                        Ну или напишите аналогичную библиотеку на С. ОЙ, у вас не получится .. Потому что это невозможно..


                      1. lorc
                        14.07.2022 13:25

                        Ну смотрите. Вы привели пример, который с помощью дикой шаблонной магии на полторы тысячи строк смог сгенерировать ассемблерный код на 6 инструкций короче чем простая программа на С размером в 50 строк кода.

                        Это конечно интересный trade off. Есть чем гордиться.

                        Если я покажу другому программисту на C++ вот этот весь код - как быстро он поймет что там происходит?


                      1. Kelbon Автор
                        14.07.2022 13:29

                        Эта "дикая шаблонная магия" может генерить бесконечное множество подобных кодов. Она для того и создана. Вместо того чтобы писать это руками(никто никогда не сможет писать это руками), она делает эффективный, понятный и компилятору и разработчику код. С её помощью можно не только cat и dog сделать, а всё что угодно.

                        Потенциально эта машина всего в 1000 строк сгенерирует вам миллиарды строк качественного кода. В этом и смысл.

                        Если вам нравится раз за разом писать бесполезную херню к тому же абсолютно нерасширяемо и неправильно(тут вам указали на громадные недочёты в вашей vtable), то можете конечно продолжать. А стоило бы уже начать использовать С++


                      1. gecube
                        14.07.2022 14:04

                        Эта "дикая шаблонная магия" может генерить бесконечное множество подобных кодов. Она для того и создана. 

                        ага, только у нее две огромные проблемы. Это криптоошибки при неправильном применении шаблонов и очень долгое время компиляции. Почему какой-то чертов Rust собирает большой проект в 10 раз быстрее, чем средний проект на крестах с шаблонами ? Почему в пайтоне я получаю результат гораздо быстрее, чем в С++ ? Да даже джава - ей не нужна самая современная машина для компиляции кода


                      1. Kelbon Автор
                        14.07.2022 14:25
                        -4

                        1. Нормальные там ошибки если вы не то пишете

                        2. Нормальное время компиляции, С++20 добавляет модули, что значительно ускоряет компиляцию в сравнении с сишными инклудами

                        3. Раст компилируется дольше С++, это просто факт.

                        4. В питоне вы получаете результат дольше, потому что он работает дольше...


                      1. Racheengel
                        14.07.2022 19:43

                        Вот про "нормальность" и "факт" хотелось бы с доказательством, а то как-то совсем голословно получилось...


                      1. Kelbon Автор
                        14.07.2022 13:31

                        Покажите мне любой сишный код и я укажу, что вы инклудите тонны кода. Но это вас почему то не смущает


                      1. Chaos_Optima
                        14.07.2022 12:43

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


          1. lorc
            14.07.2022 10:28
            +4

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

            И где там потеря производительности? Что вызывать функцию через vtable, что по указателю - один хрен.

            Как-то коммитету по стандартизации С++ получается держать стабильное ABI.

            Да? Я вообще не встречал описаного C++ ABI. Тем более в стандарте. Насколько я знаю, у каждого компилятора свой ABI. Грубо говоря, вы не сможете статически слинковать вместе объектные файлы сгенерированные gcc и msvc. MSVC не поддерживает стабильное ABI даже между версиями, кстати: https://stackoverflow.com/a/67844737

            и чё? Как это мешает то?

            Ну их как бы надо динамически линковать. Делать это не имея стабильного ABI - то еще развлечение.

            Лучше покажите как на С сделать "класс" не выделяя его в куче

            Кто мне мешает выделить структуру на стеке? :)
            Более того, я могу выделить структуру (и вообще любой другой объект) на стеке динамически. Благодаря магии alloca.

            Ну или как прочитать строку, пришедшую в мейн с неизвестным размером

            А в чем проблема? realloc никто не отменял.


            1. Kelbon Автор
              14.07.2022 12:01
              -4

              Кто мне мешает выделить структуру на стеке? :)Более того, я могу выделить структуру (и вообще любой другой объект) на стеке динамически. Благодаря магии alloca.

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

              К тому же код с этим выглядит чрезмерно ужасно

              А в чем проблема? realloc никто не отменял.

              вот напишите код и увидите в чём проблема, сколкьо можно талдычить очевидные вещи


              1. lorc
                14.07.2022 12:17

                Это нестандартный С и это ухудшает значительно полученный в итоге ассемблер.

                Ну я ж не говорю что это нужно использовать. Вообще ни разу не использовал alloca и не видел чтобы его использовали где-то. Но он есть. И да, ассемблеру x86 например вообще пофиг на такое. Он все равно восстанавливает правильное значение SP при выходе из функции.

                вот напишите код и увидите в чём проблема, сколкьо можно талдычить очевидные вещи

                Зачем так нервничать? Ну писал я код который использует realloc. Ничего ужасного.


        1. truthfinder
          14.07.2022 10:52
          +2

          По мнению автора статьи выходит, что весь код ядра линукса UB. А статью на хабре никто не помнит уже, где компилятор плюсов оправдывал стандартом вызов кода, который не должен был вызываться в принципе?


          1. F0iL
            14.07.2022 12:20
            +2

            Вот эта статья: https://habr.com/ru/company/infopulse/blog/338812/
            Правда, при компиляции сишным компилятором безо всяких там плюсов оно ведет себя точно так же, вызывая невызываемую функцию: https://godbolt.org/z/W85MWr47e


  1. dd1911
    13.07.2022 21:03
    +41

    Я специально зарегистрировался что бы оставить этот комментарий.
    Устал слышать этот бред.
    Все говорят С это embeded. Вопрос только когда все так решили?
    Вот про это мне интересно почитать статью и даже очень.
    Когда все переписали на С++, когда С++ начал жить полноценно. Когда многие репозитории переписали те самые 5-10% С кода?
    Я начну с низов, много графических библиотек без С? Так или иначе большинство библиотек с которыми я работаю, основываются на С или частично зависят от него.
    Skia / SDL / Qt / GTK / ect.. Вы говорить что С++ с UB это не C++ (тогда что?) потому что это огромное число софта, которое все называют C++. Ладно это мелочи.
    Но каждый раз я слышу С этот embeded и меня прям трясет. Потому что наверное большую часть софта с которым я работаю, написано на С и С++. Зачастую вместе. Я не понимаю, почему люди так открещиваются от С и говорят это только embeded. Хотя наверное эти люди считают embeded всем? От микроконтроллеров до графических систем вроде OpenGL / Vulkan. GUI, Gamedev, OC, Сервера, прокси, другие языки программирования и так далее можно долго. Зачем я все это написал?
    Обидно слышать что С это embeded, а без него... Я бы не имел софта которым пользуюсь.
    И пользуются люди по всему миру!

    Что раньше появилось курица или яйцо? Да это и не важно, но как мне видится.
    Мир без С++ будет сложен, а без С невозможен. Мое личное мнение!


    1. Kelbon Автор
      13.07.2022 21:19
      -30

      Какой смысл сейчас использовать С там, где существует компилятор С++?


      1. omxela
        13.07.2022 21:47
        +9

        Какой смысл ...

        А это смотря что Вы понимаете под "смыслом". Та или иная парадигма, тот или иной язык выбирается не по хайпу (хотя Вы именно за это и топите), а по задаче. В этом смысле структурный подход может оказаться проще и эффективнее любого другого для данного конкретного проекта. А ООП - для другого конкретного проекта. Можно, конечно, делать вид, что компьютера как двоичного автомата не существует. Но я Вас удивлю. Любая, даже самая продвинутая, модель данных - это всего лишь тупой набор байтов. Доказательство - скомпилированный код. Взгляните на досуге. И если Вы действительно хотите отдавать себе отчёт в том, что Вы делаете, то без этих байтиков никак. А уж декларативно или императивно - определяется, повторюсь, задачей, да ещё традициями команды, пожалуй.


        1. 0xd34df00d
          14.07.2022 06:19
          +5

          Вы вполне можете писать на C++ в структурном стиле. Но при этом у вас будут ещё и все фишки плюсов: чуть большая типобезопасность, чуть большая выразительность, RAII какой-нибудь (который вполне может скомпилироваться в тот же код, что и вы руками будете писать на C), чуть больше средств для обобщения вроде шаблонов, чуть больше готовых алгоритмов из STL вроде всяких std::all_of (зачем это писать руками?).


          Я ненавижу плюсы (потому что потратил на их тонкости, совершенно не переносящиеся на любой другой язык или деятельность, этак 17-18 лет жизни из своих 31, включая самые сочные, когда я мог бы ботать матан или, в конце концов, с девочками за ручку ходить) и презираю ООП (потому что, ИМХО, это очень неудачный базис для разложения программ), но не вижу смысла использовать C вместо плюсов, кроме, возможно, трёх случаев:


          1. Под вашу целевую платформу нет компилятора плюсов, а сей — есть.
          2. В вашей команде нет плюсистов.
          3. Вы работаете над сишным легаси.

          На сдачу — если вы пишете сишную обвязку над библиотекой на плюсах/хаскеле/етц и используете его в качестве того самого lingua franca. Но C в этом случае не является языком реализации.


          1. Admz
            14.07.2022 07:26
            +1

            А вы бы могли поделиться с нами на что лучше бы потратили своё время, как личное так и профессиональное. Я думаю что многим, особенно те кто мечтает "войтивайти" за баблом, будет познавательно на что всё-таки тратить свои лучшие годы и энергию. Какой совет вы бы дали себе 20 летнему?


            1. 0xd34df00d
              14.07.2022 08:07
              +2

              От интересов зависит. Я бы, наверное, порекомендовал себе лично тратить больше времени на фундаментальную математику и на сон.


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


          1. DabjeilQutwyngo
            14.07.2022 10:25
            -1

            презираю ООП (потому что, ИМХО, это очень неудачный базис для разложения программ)

            Так это базис языка и мышления в англоязычной культуре. Более того, видимо, кроме концепций (представленных на начальному уровне классами, а в общем случае шаблонами, посредством которых производятся описания уточнённых концепций), представленных как отношение, и их применения (т.е. выражений из терминов, обозначающих применяемые концепции), иное невозможно, т.к. иначе придётся заниматься подстановкой элементов в формулы, определяющие концепции, и плодить неимоверное количество подобных информационных структур.

            Применение теории множеств и отношений, выразившейся в сказанном выше, аналогично применению архивирования (т.е. сжатия и распаковки). Поэтому же в конструкции классов и ассоциаций в UML общим предком является Classifier, а принципиальная разница между ними лишь в отсутствии поведенческих фич у вторых и возможности определения вложенных классов. А для понимания ООП очень полезно изучить таксономию классификаторов UML (производных от Classifier).


      1. alexac
        13.07.2022 22:27
        +10

        Есть смысл, на самом деле. C - это lingua franca. Когда нужно дружить друг с другом код на разных языках, зачастую все сводится к предоставлению C-интерфейса. И может быть в имплементации этого интерфейса будет уже C++, go, rust, ассемблере или вообще чем-то экзотичном. Но интерфейс будет на C потому что подцепиться к нему можно из максимально широкого круга языков. Писать весь проект на C, мало кто будет, но какие-то части регулярно получаются написанными на C или хотя бы представляют из себя интерфейсы на C.


        1. Kelbon Автор
          13.07.2022 22:47

          extern "C"

          Потому что вам нужно не писать на С, а просто не манглить имя функции чтобы её экспортировать


        1. lorc
          13.07.2022 22:59
          +1

          Потому что на каждой платформе C предоставляет стабильный ABI: как представлять типы в памяти, как вызывать функции, как передавать в эти функции параметры, как возвращать результаты. Никакой другой язык это не делает.


      1. Icon0clast
        13.07.2022 22:28
        +6

        Это может конечно вкусовщина (да кого я обманываю, так и есть) но C++ достаточно перегружен и в некоторых задачах его мощь и сложность просто ненужны. Кресты иногда сподабливаются пушке по воробьям — дорого, тяжело и глупо.


        1. isadora-6th
          14.07.2022 11:19
          +2

          Всегда использую std::vector даже в ситуациях, где хватило бы std::array или Сишного[].
          Потому что расти проще. Если я положу туда стракты, я уверен, что ничего с моими std::string не произойдет, они не потеряются.
          Я могу просто СКОПИРОВАТЬ struct -> struct, без мыслей о том, что блиииин у меня висит char* в двух страктах, где его почистить.

          Я просто пишу реализацию std::less лямбдочкой, что-бы посортировать этот самый вектор.
          Можно очень долго думать про оверхеды. Но будем откровенны, если на каждое место в коде думать про оверхед, код написан не будет.
          Нет смысла бороться за каждый такт в коде который вызовется 1-2 раза.

          Если у тебя есть пушка, то зачем гоняться за воробьями с ножом?


          1. Icon0clast
            14.07.2022 19:01
            +1

            Вы немного спутали вопрос (не в последнюю очередь благодаря неточности моей речи) одно дело писать небольшие (или любые вообще) программы в которых не предполагается изменение, долгая поддержка и т.д. то бишь утилиты, и совсем другое проекты, которые вы планируете расширять и улучшать. В первом случае есть повод не заморачиваться с абстракциями вроде std::vector и ему подобными, а сделать тупо массив, есть повод не использовать ООП и другие достижения цивилизации.
            Совершенно другое дело, писать программы с заделом на будующее. В таком случае использование абстракций вполне оправдано. И C++ оправдан в таком случае.
            Говоря языком метафор: вам не нужен отбойный молоток, чтобы забить гвоздь в стену. А коли вы возьмётесь за серьёзное строительство, тогда да, почему бы и не воспользоваться таким громоздким инструментарием.


      1. embedded_bat
        14.07.2022 17:57

        Наверное люди просто ненавидят С++, раз он такой классный во всех отношениях, но всё равно не смог за десятилетия заменить С во всех нишах.


        1. F0iL
          14.07.2022 18:11

          Не надо недооценивать широко распространенный синдром под названием "здесь так принято".


        1. eao197
          14.07.2022 20:19
          +1

          Наверное люди просто ненавидят С++

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

          Я ненавижу плюсы (потому что потратил на их тонкости, совершенно не переносящиеся на любой другой язык или деятельность, этак 17-18 лет жизни из своих 31, включая самые сочные, когда я мог бы ботать матан или, в конце концов, с девочками за ручку ходить)

          Так что да, фактор "не люблю и все" имеет место быть.


          1. 0xd34df00d
            14.07.2022 22:45

            Но я-то эти люди-то не на сишку же перешли.


    1. domix32
      13.07.2022 22:39
      +1

      С это embeded

      А эти люди сейчас с нами в одной комнате?


    1. includedlibrary
      13.07.2022 23:34

      Я это утверждение немного по-другому понимаю - нет смысла начинать новый проект на си, если это не embedded. Особого профита вы не получите, но зато получите кучу потенциальных ошибок. Существуют языки, которые с помощью сильной системы типов позволяют множество ошибок сделать невозможными, поэтому странно начинать новый проект на си, если есть возможность этого не делать


      1. Source
        14.07.2022 02:50
        +4

        По такой же логике можно сказать, что нет смысла начинать новый проект на C++. Особого профита вы не получите, но зато получите кучу потенциальных ошибок)

        Я такого рода утверждения уже больше 10 лет постоянно слышу. А люди зачем-то всё начинают и начинают.

        Существуют языки, которые с помощью сильной системы типов позволяют множество ошибок сделать невозможными

        Ну, вот это точно не про С++. Это вам не Haskell, не Idris и даже не Rust в плане системы типов.


        1. includedlibrary
          14.07.2022 09:40

          Я аналогичного мнения насчёт c++ придерживаюсь.

          Я такого рода утверждения уже больше 10 лет постоянно слышу. А люди зачем-то всё начинают и начинают.

          Я не отрицаю, что есть специфические области, где c и c++ необходимы. Например, в игровой индустрии движки на c++ написаны, поэтому новые игры пишутся на нём.


      1. mikhanoid
        14.07.2022 10:23

        Просто по опыту, при программировании на Си ошибки в типах - не самые часто встречающиеся ошибки. Как и при программировании на языке с более сложной системой тимпов, основные ошибки алгоритмические. А от этого никакая система типов не спасёт.


        1. includedlibrary
          14.07.2022 11:07

          Просто по опыту, при программировании на Си ошибки в типах - не самые часто встречающиеся ошибки.

          По-моему опыту самые частые ошибки - это segmentation fault, выход за границу массива, переполнение числовой переменной, ошибки при работе с указателями. Плюс нужно следить, что твой код не является UB. Ко всему этому ещё и алгоритмические ошибки добавляются.

          Как и при программировании на языке с более сложной системой типов,
          основные ошибки алгоритмические. А от этого никакая система типов не
          спасёт.

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

          Я не считаю, что всем нужно использовать зависимые типы и доказательства. Я считаю, что нужно минимизировать использование языков, в которых существуют ошибки легко устраняемые компилятором. На том же rust низкоуровневый код создавать много приятнее и безопаснее, потому что нет UB, проблем с обработкой строк, сегфолтами, указателями и ручным управлением памятью. Понятное дело, что при взаимодействии со сторонним сишным кодом многие из этих проблем всплывают, но опять же только в нескольких местах, а не во всём коде проекта


        1. 0xd34df00d
          14.07.2022 16:48
          +3

          Как и при программировании на языке с более сложной системой тимпов, основные ошибки алгоритмические. А от этого никакая система типов не спасёт.

          Мы с вами это регулярно обсуждаем, и вы регулярно пишете, что не спасёт, а я регулярно пишу, что некоторые — спасут.


          Как там битонная сортировка, кстати? :]


    1. 0xd34df00d
      14.07.2022 05:56
      +5

      Так или иначе большинство библиотек с которыми я работаю, основываются на С или частично зависят от него.
      Skia / SDL / Qt / GTK / ect..

      Можете сказать, где в Qt есть C в значимых количествах (кроме ОС, на которой оно в итоге исполняется, конечно)?


      Вы говорить что С++ с UB это не C++ (тогда что?)

      Не C++. Компилятор может полагать, что в программе на C++ UB не бывает.


    1. pai3eji
      14.07.2022 06:29
      -2

      >>Все говорят С это embeded.

      полагаю вы это понимаете как "непригоден для чего-либо кроме embed", но говорящие так [опять же полагаю] имеют ввиду что то типа "он тут ненужен".

      >>Вопрос только когда все так решили?

      а потому и непригоден ненужен он стал, когда стало модным реализовать GUI посредством вкрячивания целого браузера в каждый второй hello world и не абы какого а свежего хромиума, заказывая верстку у джунов пашущих "за еду"... вспомните во что превратились тот же skype, wot...

      помнится, как раз тут на хабре лет эдак много назад кто-то хвастался как "изящно" парой строк кода призвал уведомление в трэй. только эти его пара строчек кода скомпилировались в exe весом 50+Мб...

      впрочем, чего это я на хромиум взъелся... сейчас же контейнеризация в моде, а это на минуточку, развёртывание по целой ОС на каждое приложение *pokerface*. и ведь с точки зрения ИБ, только так и надо...


    1. Moraiatw
      14.07.2022 16:20
      +1

      Добавьте еще nginx.

      Видимо тоже "emdedded"


  1. Sazonov
    13.07.2022 21:40
    +6

    В вакансиях указывают C/C++ когда ищут человека на проект, в котором тонны спагетти кода, которые писали не очень хорошие си-программисты на языке «си-с-классами».

    А вообще я сам сейчас на проекте где есть и чистые си приложения и приложения на хорошем с++. Скажу по себе - действительно очень сложно переключаться с си++ мышления на си. Очень не хватает шаблонов и деструкторов. Но постепенно начинаешь пользоваться определенными практиками и жить становится можно, хоть и неудобно. Не считаю себя хорошим си программистом, после си++ на нём очень тяжело писать (хотя когда я начинал, я писал на чистом си/винапи)


  1. WhiteWhiteWalker
    13.07.2022 21:46
    +3

    А ничего, что требования и подход != язык? Да, в современном С++ есть RAII и лямбды, но это лишь еще +1 вариант написания функционала, те N вариантов, что были до этого, работать не перестанут. С++ как развитие С необходимо для: уменьшения количества кода, улучшения читабельности (и как следствие, броня ноги +1), развитие стандартной библиотеки для кроссплатформенности. Но того же сокращения кода можно добиться и макросами и goto, что будет лучше циклов внутри циклов или шаблонов с переменным количеством аргументов. Да и интерфейсы динамических библиотек всегда сначала оформляются в C, а затем уже пишется обёртка на С++.


  1. AllKnowerHou
    13.07.2022 21:46
    -1

    За что лайкают статью - непонятно, но и дизлайкать тоже не за что


    1. savostin
      13.07.2022 22:12
      +18

      Я, возможно, выражу общее мнение:

      "И чо?"


  1. funca
    13.07.2022 22:20
    +4

    Мне кажется C/C++ появился с подачи Microsoft. В свое время Visual C был именно таким мутантом, толком не поддерживающим ни тот и не другой стандарт. При этом код стандартных библиотек представлял собой ацкую смесь с элементами обоих языков (а может где-то и сейчас так).


    1. domix32
      13.07.2022 22:40
      +4

      Ждем когда они отчебучат Rust/Verona


  1. KivApple
    13.07.2022 22:49
    +9

    Во-первых, 95% Си совместимы с плюсами. При должной аккуратности можно писать код совместимый с обоими языками, причём ifdef потребуется только для extern "C", если нужна интероперабильность. Просто надо будет расставлять больше приведений типов и не использовать пару сишных фич.

    Во-вторых, из плюсов очень часто вызывается большое количество сишных библиотек. Так что программисту на плюсах нужно знать Си (но это не сложно зная плюсы, см. первый пункт) всё равно.

    В итоге либо нужен только Си, либо оба языка.


    1. yeputons
      14.07.2022 02:11
      +2

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

      При этом знать goto/setjmp на Си, мне кажется, надо почти всегда, а вот в C++ без этого можно довольно долго жить.


  1. FlameStorm
    13.07.2022 23:35
    +9

    Зачем писать на C, когда можно делать современные хеловорлды на гигабайт оперативки, вскипячение восьмиядерника и запускающегося на оси не ниже 100500й версии?

    Если без горького сарказма, то всему своё конечно. Но лично мне нравится подход к С++ как к C (с дурацкими байтами) с ООП классами. И соответственно мышлением где равноважными являются оба компонента - и предметная область и её формализация через ООП, и забота о эффективности по железу, мышление на уровне проца, байт оперативки, байт i/o с винтов и сети, эффективными алгоритмами, бенчмарками.

    Без унавоживания слоями чрезмерных абстракций и прочих модных шуточек вроде "для сложения двух интов давайте подтянем 1042 библиотеки на пару гигов сурцов". Либы безусловно местами незаменимая штука, но может попытаемся не терять разум?

    [ C <3 C++ ]

    PS: Еще ассемблерные вставки рулят! Asm 4eva !


    1. Kelbon Автор
      13.07.2022 23:50
      -5

      вот только С++ эффективнее С за счёт больших гарантий и большей выразительности кода


      1. FlameStorm
        14.07.2022 00:04
        -1

        Когда у нас в стране (перед лучезарным взлётом отечественного железа) будет период пятилетки-другой с двумя миллионами тыжпрограммистов на 200 000 продакшн машин и устаревающим парком техники юзернеймов, критерии эффективности всё же явно будут пересмотрены )

        А прямой ответ на коммент - да, спички детям не игрушка. Но ты же ого раз-ра-бот-чик! Если тебе дали пистолет, ну не стреляй им в ногу и в прочее куда не надо (=


        1. Kelbon Автор
          14.07.2022 06:36
          -5

          С++ компилируется в банально более хороший ассемблер, вы не верите?


          1. mikhanoid
            14.07.2022 10:27
            +1

            Я тут недавно специально сравнивал -- не компилируется. На Си, конечно, тоже надо уметь писать.


            1. Kelbon Автор
              14.07.2022 10:30
              -2

              А может на С++ вы писали что то странное?


              1. lorc
                14.07.2022 10:54
                +3

                Ага, значит надо писать что-то "нормальное"? Можете дать какие-то критерии как отличить "странное" от "нормального"?


                1. Kelbon Автор
                  14.07.2022 11:48
                  +1

                  покажите код


                  1. lorc
                    14.07.2022 12:40
                    +1

                    Это у @mikhanoid надо спрашивать


          1. Moraiatw
            14.07.2022 16:31
            +1

            С++ компилируется в банально более хороший ассемблер, вы не верите?

            Нет.


            1. mapron
              14.07.2022 21:20
              +1

              Как разработчик на С++ я тоже в это не верю. Возможно автор комментария про какие-то узкие кейсы по типу sort() который на C работает с void* и не может оптимизировать под конкретные типы и все такое. Но если не читерить с кейсами
              «вот мы на С++ сделали шаблонный код, а на С такое руками писать утомительно поэтому сделаем тупо и неоптимально» — то не вижу причины с чего бы на С++ коду быть быстрее.
              С++ эффективнее чем С, да. В выразительности, в скорости написания чего-то большого что надо поддерживать долго и толпой мало связанных меж собой разработчиков, я думаю множество средств где в поддержке он у С может выиграть.
              А вот касаемо эффективности кода, ну чет такое. Слабо верится. Только в частностях.


    1. Akon32
      15.07.2022 09:12

      Еще ассемблерные вставки рулят!

      Это пока программа запускается на одном компьютере типе процессора, а если говорить об оптимизации - на одной модели процессора. Потом через какое-то время ВНЕЗАПНО начинает рулить java. Или даже python.


  1. GospodinKolhoznik
    14.07.2022 07:13
    +10

    Правильно писать C/C++/1C


    1. 0xd34df00d
      14.07.2022 08:08
      +8

      /C#/Cobol


      1. artemisia_borealis
        14.07.2022 17:09

        /C--/Coq/C--
        (два раза это не опечатка)


      1. beeruser
        14.07.2022 21:14
        +1

        C/C++/1C/C#/Cobol/C--/Coq
        Можно и покороче:
        1?C.*


  1. DabjeilQutwyngo
    14.07.2022 08:39
    +4

    А почему вы интерпретируете обозначение "C/C++" как язык? И наоборот, с точки зрения теории формальных языков, почему объединение всех возможных цепочек языков C и C++ не будет языком? С чего вдруг операция объединения языков перестала быть замкнутой в полукольце языков?

    Символ "/" тоже следует интерпретировать как концепцию совместного использования или варьирования. Есть ведь ещё и CLI-расширение языка C++ для .NET. И как тогда прикажете сообщать, что требуется (кандидат может/программа написана с) применять и C, и C++, и CLI?

    Копая дальше, а откуда такое предубеждение, что мозг может эффективно работать исключительно в одном стиле программирования? Вы ведь выражаете мысли и на естественном языке в программном коде, используя хотя бы говорящие наименования, не говоря уже про прямое документирование. Вам борьба за чистоту языка или стиля программирования (абстрактно -- множества концепций) не напоминает борьбу за "чистоту" крови, нации или расы?

    Если копнуть ещё глубже, и посмотреть, как устроены живые системы (их изучением занимается системная биология), то выяснится, что природа использует носителей, максимально эффективно накаченных функциональностью. Т.е. и на уровне атомов, и на уровне молекул, и на уровне макромолекул, не говоря уже про их комплексы, метаболиты, в частности. Даже одна молекула (определена структурной формулой) часто проявляет множество биологических активностей. Однако, совмещение функциональности на одном носителе (объединение языков, например) многими осуждается в программировании. Как и совместное использование разных стилей. Хотя оракловые SQLJ как и PL/SQL очень даже удобны и эффективны.

    Проверим этот подход сравнением по уровню сложности ИТ-систем, созданных людьми, с живой системой, да хотя бы человеком. У человека собственных клеток порядка 37 триллионов, и 23 триллиона живущих с ними в симбиозе. Одна клетка -- как небольшой завод на полном вертикальном обеспечении: включает и выработку энергии, и производство, и доставку к местам трансформаций всех компонент (от базовых деталей, т.е. простых молекул и аминокислот до молекулярных роботов, коими выступают белки и метаболиты, в частности), требующихся для жизнедеятельности клетки. А главное (о ужас!), в каждой клетке одна и та же ДНК, служащая исходным кодом (система нуклеотидных последовательностей: уложены в хромосомы), хотя многобразие клеток очень велико. И стволовые клетки могут трансформироваться в большое разнообразие других клеток. Т.е. природа несравненно превосходит по сложности всё то, что пока человеческий мозг смог сконструировать и понять. И это ещё не касались устройства систем управления на разных уровнях, особенно нервной системы и мозга. Природу нисколько не заботило требование понятности для кого-либо: функциональность важнее.

    Так зачем вам разделение по языкам, по стилям программирования и запрет их совмещения на одном носителе (как программисте, так и исполняемом модуле)? Ради индивидуальной понятности это бессмысленно. Ради поддержания функциональной закреплённости ещё и вредно. Так зачем?


    1. 0xd34df00d
      14.07.2022 16:50
      +1

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

      Потому что C и C++ назначают некоторым одинаковым синтаксическим конструкциям разные семантики.


      1. DabjeilQutwyngo
        14.07.2022 22:57

        И чтобы эту неоднозначность устранить, есть extern "C". А может быть и extern "SQL", и много других языковых приёмов. Более того, многозначная интерпретация не всегда взаимоисключающая, и есть масса случаев, когда она одновременно верная. А взаимоисключающая интерпретация часто возникает даже в одном языке, для чего вводят дополнительные факторы: пресловутый пример с if-else. Многозначная интерпретация и её обработка -- основная проблема разработки таблицы трансляции, т.е. перевода некоторой комбинации из элементов языка во что-либо (другую цепочку или действие). Сложность этих комбинаций и их многообразие является следствием класса языка.

        Более того, семантика содержится вне языка, как и прагматика: разные языки могут описывать и предписывать одно и тоже. И ключевой характеристикой языка является его выразительная способность (описательная мощность). Именно поэтому есть понятие "синтаксически управляемый перевод", и весь ИТ построен на его применении и вокруг этой проблемы, т.к. для оперирования информацией требуется носитель. Напомню, что язык, по определению, -- это подмножество произвольной итерации алфавита, т.е. подмножество универсального языка.

        Поэтому ваше справедливое наблюдение про различие семантики, поставленной в соответствие цепочкам языка, не является ни критерием, ни признаком, но является закономерным эффектом существования пересечения таблиц трансляции по входным комбинациям элементов языка.


        1. 0xd34df00d
          14.07.2022 23:37

          И чтобы эту неоднозначность устранить, есть extern "C".

          wat.jpg


          int meh()
          {
              return sizeof('a');
          }
          
          extern "C"
          {
              int foo()
              {
                  return sizeof('a');
              }
          }

          тут обе функции вернут 1.


          То есть тут я, конечно, поступаю нестрого, рассматривая язык ещё и как его семантику, но для обсуждения сей и плюсов это разумная нестрогость, на мой взгляд.


          Впрочем, даже чисто синтаксически вы в extern "C" блоке не можете написать int class;, а в C — можете.


          Многозначная интерпретация и её обработка — основная проблема разработки таблицы трансляции, т.е. перевода некоторой комбинации из элементов языка во что-либо (другую цепочку или действие).

          Почему у вас везде вылезают таблицы? Вы что, студент с блохой?


  1. bolk
    14.07.2022 08:55
    +1

    Гугл, может, и не знает, но «Вики» вполне знает о развитии Си: https://ru.wikipedia.org/wiki/C11


    1. mikhanoid
      14.07.2022 10:31
      +1

      https://en.m.wikipedia.org/wiki/C2x - даже так. Но не факт, что это всё на пользу языку. Всё же, хотелось бы, чтобы KISS.


  1. khe404
    14.07.2022 11:52

    Прочитал я статью и задумался, решил перевести на понятный мне "С/С++", дабы ,было легче читать и вот что получилось:

    bool inconsistency_in_technical_article=false; 
    Date date{"01/01/1983"};
    ArticlesLibrary al;
    std::map<std::string,bool> languages; //  {{"C/C++",true},{"C",false},{"C++",false},OTHER_LANGUAGES};
    langages = getAllLangauges();
    //Каждый день
    while(++date){
      //везде
    	auto article = al.getNext();
      //появляется язык С/С++
      auto lit = languages.find("C/C++");
      if(lit==languages.end()){
     		throw std::system_error(); // если такого языка нет то это вообще коллапс
      }
      // И он мифический 
      bool is_mythical = lit->second;
      auto found = article.search(lit->first);
      if(found==article.end())
      	throw std::system_error(0);  // если не везде то с системой что то не так
      if(article.isTechnical)
      	inconsistency_in_technical_article=true; // даже в технических статьях
      auto [l1,l2] = split(lit->first,"/");
      explain_difference(l1,l2); //todo more C: printf("%s != %s",l1,l2); ... 
    	auto c_language = redefine_language("C");
      auto cpp_language = redefine_language("C++");
      ASSERT(c_language!=cpp_language);
      lets_finally_think(); // пора бы уже задуматься 
    }

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

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

    В общем, хорош вносить смуту в ряды С/С++ программистов, лучше пойдемте вместе побеждать питоноидов. :)


  1. nadoelo
    14.07.2022 13:09
    +1

    Посыл хороший, но орфографические ошибки и опечатки очень сильно портят читаемость


  1. Vfedosov
    14.07.2022 17:02

    С++ по сути надстройка над С. Сейчас стандарты чуть чуть разошлись, но большая часть си кода отлично работает на С++. Насчет того, что классы не байты и си код это неопределенное поведение - бред. Есть в стандарте плюсов и правила выравнивания полей классов по байтам. Хороший программист С++ всегда учитывает, как поля класса распределены по байтам - позволяет выжать больше из языка. И указатели работают отлично на с++ и все еще очень даже в ходу - особенно при оптимизации. И декларативное программирование обычно занимает меньше половины кодовой базы на плюсах - если не считать библиотеки шаблонных классов и прочие малочитабельные вещи. Если человек считает себя спецом по плюсам, то основы си он знать должен - иначе не поймет значительную часть кода библитек и легаси. Обратное конечно не верно. Так что, если автор выбрал для себя какую-то часть языка С++, как более понятную и приятную, это не значит, что остальная часть языка забыта и не используется.


  1. F0iL
    14.07.2022 18:16

    Ну и раз уж тут такое веселье в комментариях, не могу не оставить тут ссылку на старую статью:

    https://habr.com/ru/post/585428/


    1. rogoz
      14.07.2022 23:15

      Вы пытаетесь открыть публикацию, написанную пользователем F0iL, однако, публикация скрыта в черновики (самим автором или НЛО)


      1. F0iL
        15.07.2022 08:00

        Точно. Не та ссылка. Вот тут ещё доступно:

        https://itnan.ru/post.php?c=1&p=585428


  1. sergey-kuznetsov
    14.07.2022 18:52

    Это как путать -тся и -ться. Слова выглядят одинаково казалось бы, но смысл совершенно разный.


  1. oleg_shamshura
    15.07.2022 09:46

    Когда пишу в резюме C/C++, имею в виду "могу так, могу этак".
    Видимо, придется обозначать по-другому: C|C++


    1. F0iL
      15.07.2022 10:02

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


      1. Jian
        15.07.2022 13:02

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


        1. F0iL
          15.07.2022 13:35

          В моей практике встречались случаи, когда разные части одной и той же программы были написаны на смешанном коде C++ и JavaScript с довольно плотным их взаимодействием и объектами пошаренными между ними, но указывать используемый язк как "C++/JS" почему-то в голову никому не приходило.

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


          1. Jian
            15.07.2022 13:37

            Когда начинали писать C/C++ смешивать их в одной программе было общепринятой распространённой практикой.


            1. F0iL
              15.07.2022 18:00

              Ну мы то сейчас живём в 2022, а не в 1992. К тому же автор изначального комментария говорил о "могу так, могу этак", а не про смешивание двух языков в одной программе.


    1. Akon32
      15.07.2022 11:40
      +3

      Так и до C\C++ недалеко.


      1. sci_nov
        15.07.2022 22:35

        М\Ж


  1. Ais_Zuhelcer
    15.07.2022 09:51
    +1

    Что и говорить про провинциальные колледжи и вузы... Особенно веселит когда приходит очередной препод и говорит: "Сейчас, Я вас буду учить программированию, показывает Си-шный код и говорит мы будем изучать С++". А ты у него спрашиваешь в конце лекции: "...так мы изучаем Си или С++, и можно ли писать в C++ стиле?" - он смотрит на тебя с недоумевающим видом и либо переспрашивает, либо начинает поднимать тебя на смех.


  1. incogn1too
    15.07.2022 11:54

    Абсолютно не согласен.


  1. ormuzd
    15.07.2022 14:45

    Наверно имеется ввиду, что человек должен знать С и С++, что не удивительно.
    Вообще было забавно читать весь этот бред о том, что нельзя реализовать простой вектор на С, потому что язык тебе этого не даст сделать.
    Столько программ написано на С, все *nix на нём. А у некоторых вектор не получается реализовать. Что это может говорить? Только об уровне владения знаниями авторов подобных утверждений.
    И как говорил старина Торвальд - "C++ можно использовать только если выкинуть из него всё д*рьмо, чтобы остался по итогу чистый С" )


    1. Jian
      15.07.2022 14:54

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

      C является тьюринг-полным и потому эмуляцию подобного вектора возможно написать. :)

      #ifndef CVECTOR_H_
      #define CVECTOR_H_
       
      #include  // для функций работы с памятью
      #include  // также для некоторых функций для работы с памятью
       
      //Стандартный размер вектора при инициализации
      #define CVECTOR_INIT_CAPACITY 4
       
      /*
      * Структура, представляющая собой "объект" вектора.
      */
      typedef struct{
      void** data;
      int size;
      int capacity;
      size_t element_size;
      } cvector;
       
      #endif /* CVECTOR_H_ */
      #ifndef CVECTOR_H_
      #define CVECTOR_H_
       
      #include  // для функций работы с памятью
      #include  // также для некоторых функций для работы с памятью
       
      //Стандартный размер вектора при инициализации
      #define CVECTOR_INIT_CAPACITY 4
       
      /*
      * Структура, представляющая собой "объект" вектора.
      *
      */
      typedef struct{
      void** data;
      int size;
      int capacity;
      size_t element_size;
      } cvector;
       
      /*
      * Инициализация структуры вектора.
      *
      * @param __v указатель на структуру вектора
      * @param __dataSize размер элемента данных в байтах
      */
      void cvector_init(cvector* __v, size_t __dataSize);
       
      /*
      * Функция, которая возвращает текущее количество.
      * элементов в векторе
      *
      * @param __v указатель на структуру вектора
      */
      int cvector_size(cvector* __v);
       
      /*
      * Функция добавления данных в конец вектора.
      *
      * @param __v указатель на структуру вектора
      * @param __data указатель на данные
      */
      void cvector_push(cvector* __v, void* __data);
       
      /*
      * Функция изменения элемента вектора по индексу.
      *
      * @param __v указатель на структуру вектора
      * @param __index индекс элемента
      * @param __data указатель на новые данные
      */
      int cvector_set(cvector* __v, int __index, void* __data);
       
      /*
      * Удаление элемента из вектора по индексу.
      *
      * @param __v указатель на структуру вектора
      * @param __index индекс удаляемого элемента
      */
      int cvector_delete(cvector* __v, int __index);
       
      /*
      * Получение значения элемента по индексу.
      *
      * @param __v указатель на структуру вектора
      * @param __index индекс элемента
      */
      void* cvector_get(cvector* __v, int __index);
       
      /*
      * Полная очистка вектора.
      *
      * @param __v указатель на структуру вектора
      */
      void cvector_clear(cvector* __v);
       
      void cvector_resize(cvector* __v, int __newCap);
       
      #endif /* CVECTOR_H_ */

      Взято от сюда http://tetraquark.ru/archives/66


      1. 0xd34df00d
        15.07.2022 17:51
        +1

        А как сделать так, чтобы вектор был только из элементов типа


        struct Foo
        {
          int a;
          double b;
        ];

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


        Поможет тут тьюринг-полнота?


        1. Akon32
          15.07.2022 22:00

          ЕМНИП была какая-то техника обмазывания дефайнами, которая сводит копипаст программиста (но не препроцессора) к нулю; наверно, и ошибки препроцессором можно проверять.

          Но что интересно в примере - тип элемента там полностью описывается лишь размером элемента, да ещё и проверка возможна лишь в рантайме. Динамическая типизация на минималках, однако.


          1. 0xd34df00d
            15.07.2022 22:23

            ЕМНИП была какая-то техника обмазывания дефайнами, которая сводит копипаст программиста (но не препроцессора) к нулю; наверно, и ошибки препроцессором можно проверять.

            В качестве вопроса со звёздочкой предлагаю реализовать гетерогенный лукап в гипотетической сишной мапе (перегрузки 3-4 здесь).


        1. beeruser
          15.07.2022 22:02

          Самый удобный «вектор» на C — это «stretchy buffers».
          ourmachinery.com/post/minimalist-container-library-in-c-part-1

          Динамический массив будет выглядеть и работать как обычный указатель:
          struct Foo *array;
          Дополнительные данные (size, capacity) лежат перед первым элементом.
          И никакого дублирования кода.


          1. 0xd34df00d
            15.07.2022 22:22
            +1

            Нашёл реализацию, и у меня остаётся вопрос:


            А как сделать так, чтобы [...] компилятор выдавал мне ошибку, если я туда попытаюсь засунуть что-то ещё или прочитать что-то ещё? stb_sb_push не выглядит особо проверяющим типы.