Задать вопрос
Ответы пользователя по тегу C++
  • Как считать из stdin русский текст и вывести его как wchar_t?

    @res2001
    Developer, ex-admin
    blecked88, Было свободное время, провел несколько экспериментов, т.к. про _setmode впервые у тебя увидел.

    Если вместо _O_U16TEXT использовать _O_U8TEXT, то ввод/вывод будет преобразовываться в UTF8, что более привычно (чем UTF16). Особенно это заметно при выводе строк (ввод как раз лучше оставить в UTF16) в файл (например если в консоли сделать перенаправление вывода в файл, а затем файл открыть в текстовом редакторе).

    Вообще, учитывая, что кодировку консоли может устанавливать пользователь самостоятельно, то чтоб было совсем красиво надо перекодировать выводимые строки в кодировку консоли, а не принудительно устанавливать свою кодировку через setmode/SetConsoleCP и т.п..
    Накидал пример, как это может выглядеть:
    Пример
    #define _CRT_SECURE_NO_WARNINGS
    #include <stddef.h>
    #include <stdint.h>
    #include <locale.h>
    #include <wchar.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    #include <io.h>
    #include <fcntl.h>
    #include <Windows.h>
    
    UINT cpo = 0;
    
    void print_wide(const wchar_t* wstr)
    {
      assert(cpo != 0);
      static char buf[512];
      if(WideCharToMultiByte(cpo, 0, wstr, -1, buf, 512, NULL, NULL) != 0)
        printf("multibyte string: \"%s\"\n", buf);
      else
        printf("Error WideCharToMultiByte()\n");
    }
    
    void main()
    {
      cpo = GetConsoleOutputCP();
      _setmode(_fileno(stdin), _O_U16TEXT);
      wchar_t wbuf[512];
      if (wscanf(L"%511ls", wbuf) == 1)
          print_wide(wbuf);
      else
          printf("Error wscanf()\n");
    
    //  const wchar_t *str = L"Привет мир!\u00df\u6c34\U0001f34c";
    //  print_wide(str);
    }

    Схема такая: внутри программы все строки хранятся как wchar_t, литералы с префиксом L. Для консольного ввода принудительно выставляем преобразование в wchar_t с помощью _setmode(U16TEXT) и используем фунции w/wcs. Настройки консольного вывода не меняем, а используем установленные пользователем или системой.
    Для вывода строк:
    1. в начале main узнаем текущую кодовую страницу консоли
    2. в функции print_wide применяем преобразование кодировки с помощью стандартной функции WinAPI.
    Пример взят отсюда. И адаптирован для ввода. Функция преобразования заменена, т.к. функция wcsrtombs из стандартной библиотеки преобразовывает только в UTF8, но не в другие доступные в консоли винды кодировки.
    Таким образом благодаря _setmode и функциям w/wcs ввод автоматически преобразовывается в wchar_t, а вывод "руками" преобразовывается в текущую кодировку консоли.
    В онлайн компиляторах пример гонять бесполезно - не понятно какие кодировки у них там при запуске.
    При компиляции в msvc файл с исходником сохранять в UTF8, добавить ключ компилятора /utf-8 (или можно сохранить файл с BOM).
    Для тестов меняем кодировки консоли руками (chcp 866/1251/65001), перенаправляем вывод в файл и смотрим кодировку текста в файле каким-нибудь доступным редактором (notepad++/far edit/...) - она должна совпадать с кодировкой установленной командой chcp.

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

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

    Статьи на тему:
    https://habr.com/ru/companies/xakep/articles/257895/
    https://habr.com/ru/companies/ruvds/articles/645325/
    https://habr.com/ru/articles/731614/
    Полезные ссылки:
    https://learn.microsoft.com/ru-ru/windows/console/...
    https://learn.microsoft.com/ru-ru/windows/win32/in...
    https://learn.microsoft.com/ru-ru/windows/win32/ap...
    https://learn.microsoft.com/ru-ru/cpp/c-runtime-li...
    https://learn.microsoft.com/ru-ru/cpp/c-runtime-li...
    Ответ написан
    Комментировать
  • Возможно ли реализовать TCP на Delphi?

    @res2001
    Developer, ex-admin
    Написал ответ в комментариях тут.
    Ответ написан
    Комментировать
  • Как сделать линковку в проекте на с++ Visual Studio?

    @res2001
    Developer, ex-admin
    Ответ в комментарии
    Ответ написан
    Комментировать
  • Как настроить CMake на установку пакетов?

    @res2001
    Developer, ex-admin
    Самому заниматься установкой зависимостей есть смысл только для статически линкуемых библиотек. В этом случае самый простой вариант такие библиотеки оформить например как субмодуль git. Тогда при клонировании вашего репозитория скачаются исходники библиотеки. В cmake просто собираете ее как отдельный таргет и используете по назначению. Хорошо если библиотека уже поддерживает сборку через cmake - будет меньше возни. Если нет, то придется написать самому для нее CMakeLists.txt.

    Для динамических библиотек стоит оставить удовлетворение зависимостей пользователю, потому что вариантов пакетных менеджеров много (вы хотите их все поддерживать?). В вашем CMakeLists.txt нужно только сделать тем или иным способом поиск установленного пакета и если его нет - выдачу ошибки и завершение сборки. Такие механизмы в cmake есть. Можно использовать выше приведенный find_package или например pkg_check_modules (который в свою очередь использует утилиту pkg-config).
    Почти все более-менее серьезные приложения не пытаются установить самостоятельно свои зависимости при сборке. Можете проверить. Например: https://github.com/nginx/nginx?tab=readme-ov-file#...

    Вы можете дополнительно к сборке приложения добавить и создание пакета для пакетного менеджера (или для нескольких пакетных менеджеров). Вот тут то вы и укажите необходимые приложению зависимости (в разных дистрибутивах линукс пакеты с зависимостями могут называться по разному). И тогда, когда пользователь будет устанавливать ваш пакет через пакетный менеджер все зависимости установятся автоматически.
    В cmake есть механизм для создания пакетов для разных пакетных менеджеров: https://cmake.org/cmake/help/book/mastering-cmake/...
    Ответ написан
    2 комментария
  • Кириллица в c++. Что с ней не так?

    @res2001
    Developer, ex-admin
    В виндовой консоли есть 2 русские кодировки cp866 и cp1251. Причем cp866 используется по умолчанию! Так же есть еще 65001 (UTF8), которая то же умеет в кирилицу. Пользователь консоли может менять кодировку по собственному усмотрению (команда chcp /?). Как правило встроенные виндовые утилиты командной строки правильно работают с любой установленной кодировкой (можете сами в этом убедиться).

    Дополнительно к кодировкам самой консоли винды добавляется еще кодировка в которой написаны ваши исходники. Кодировка исходников должна быть совместима с кодировкой консоли. Если не совместима, то нужно или переключать кодировку консоли (что для консольных утилит не хорошо - это вам пользователи утилиты потом расскажут) или перекодировать вводимые/выводимые строки на лету.

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

    Лучше исходники всегда писать в UTF8 а для строк использовать wchar_t.
    Тут и не только тут эта проблема уже обсуждалась не однократно. Например посмотрите эту ссылку: https://qna.habr.com/answer?answer_id=2278154#comm...
    Не смотрите, что там тема по Си - проблема та же самая и решения для Си и С++ будут похожие.
    Ответ написан
    Комментировать
  • Почему эта программа вычисляет факториал больших чисел неправильно?

    @res2001
    Developer, ex-admin
    Видимо ошибка в длинных вычислениях. Сложно просто глядя на код что-то сказать.
    Для оптимизации тут применена многопоточность, но похоже, что присутствуют гонки, хотя есть попытка использовать мьютекс для защиты, но явно этого не достаточно.
    Похоже, что эта программа толком не отлаживалась.

    Думаю, больше толку было бы для оптимизации, если бы использовались SIMD инструкции, а не многопоточность.
    Есть оптимизированные библиотеки для длинной арифметики, проще всего было бы использовать какую-то подобную библиотеку, а не изобретать собственный велосипед. С использованием такой библиотеки задача была бы достаточно тривиальной.
    Ответ написан
    5 комментариев
  • Данные в таком случае будут хранится в стеке?

    @res2001
    Developer, ex-admin
    Если это определение внутри функции/метода - то Number будет лежать на стеке.
    Если вне функции/метода - в области глобальных данных.
    А вот данные на которые указывает Number могут лежать где угодно.
    Да, указатель может указывать и на данные на стеке или в глобальной области. В общем на любой выделенный блок памяти он может указывать. А в вашем примере даже и не на выделенный, только обращаться по такому указателю нельзя.
    Ответ написан
  • Что будет, если не удалять графические объекты при завершении программы в C++ SDL2?

    @res2001
    Developer, ex-admin
    Система в большинстве случаев сама освободит почти все ресурсы при завершении программы. Есть исключения, но они довольно редки.

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

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

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

    Так что освобождайте все что захватывает ваша программа явно в вашем коде и не надейтесь, что кто-то это сделает за вас.
    Ответ написан
  • Проблемы с подключением заголовочных файлов на C++, как исправить?

    @res2001
    Developer, ex-admin
    Можно так:
    #include "../include/sys.h"
    Кавычки тут важны!

    Но лучше всего добавить путь поиска заголовочных файлов с помощью дополнительной опции компилятора:
    g++ -I include ...
    И подключать заголовок уже просто указывая только имя файла:
    include <sys.h>
    Ответ написан
  • Зачем передавать функцию как параметр через указатель с++?

    @res2001
    Developer, ex-admin
    Обычно callbackи так передают. Потом вызываемая функция при наступлении события сама ее вызывает.
    Ответ написан
  • Лучше ли использовать enum для цвета нежели struct?

    @res2001
    Developer, ex-admin
    Как я понимаю через выше aligment тем лучше?

    Нет. Это бред. Тут не применимы термины лучше/хуже.

    Alignment (выравнивание) - это просто свойство типа данных.
    enum по умолчанию имеет тип int, соответственно и все его свойства наследуются. В С++ (с версии 17, если не ошибоаюсь) можно самому выбрать тип enum. Для выравнивания обычно действует простое правило - тип должен быть выровнен в памяти на границу кратную его размеру. Например у int размер 4 байта (обычно), и выравнивание должно быть по границе 4 байт. у char/uint8_t - размер 1 байт, соответственно ограничений по выравниванию нет, т.е. выравнивание по границе байта. Тип SDL_Color - это, видимо, структура, состоящая из 4 uint8_t (или что там в SDL используют для unsigned char), выравнивание для структуры берется из типа ее первого поля (если аттрибутами не задано другое).
    Используй типизированный в uint8_t enum и будет тебе счастье.
    https://en.cppreference.com/w/cpp/language/enum

    Кстати, выравнивание, это не ограничение С++ - это ограничение процессора на аппаратном уровне. Правда почти все современные процессоры уже не имеют этого ограничения и нормально жуют не выровненные типы, но при этом операции выполняют медленнее, чем с выровненными. Фактически процы просто научились "маскировать" это ограничение. Поэтому ограничение в языке осталось.
    К тому же все еще есть процессоры, где требование выравнивания действует, но это в основном что-то из разряда микроконтроллеров. На таких процессорах использование не выровненных типов приводит к ошибке шины и вылету программы.
    Обычно тебе не нужно думать про выравнивание, т.к. компилятор об этом позаботится за тебя. Но бывают ситуации, когда программист должен это учитывать. Например когда ты читаешь поток бинарных данных из сети или из файла, и данные в потоке - это что-то сложнее, чем байты и символы.
    Ответ написан
    1 комментарий
  • Какой компилятор выбрать для C++?

    @res2001
    Developer, ex-admin
    Если под виндой сидишь, то используй MSVS.
    Если планируешь что-то кросс-платформенное делать, то gcc/clang в самый раз.
    Проще всего под винду использовать mingw - это сборка gcc для винды с частично портированным POSIXом.
    Сам mingw можно установить разными способами.
    Мне нравится связка msys2 + mingw. msys2 - это линуксовая оболочка со всем стандартным линуксовым окружением и пакетным менеджером pacman. С помощью пакетного менеджера можно устанавливать и mingw и clang и кучу библиотек и все это обновлять одной командой. Легко подключать к разным IDE (но не к MSVS) или запускать из командной строки винды.

    Так же под виндой можно настроить WSL в него поставить какую-нибудь ubuntu, а внутрь уже любой доступный компилятор и т.д. и т.п. По сути это виртуальная машина с линуксом.
    Ответ написан
    Комментировать
  • Безопасен ли класс для многопоточности?

    @res2001
    Developer, ex-admin
    Не безопасен.
    Вы защитили мьютексом только запись в очередь (push), но не чтение из нее (pop). Так что очередь сломается рано или поздно.
    Вообще тут лучше бы подошла какая-то специализированная структура со встроенной поддержкой многопоточности, а не стандартные контейнеры.
    Можно использовать кольцевой буфер или очередь майкла-скотта. В booste, на сколько помню, есть и то и другое.
    Но для начала сгодится и такой вариант.

    Кроме того для вывода на экран в Линукс можно учитывать тот факт, что ОС обеспечивает атомарную запись в консоль для буфера менее PIPE_BUF байт. https://linux.die.net/man/7/pipe
    Думаю в винде то же есть похожая гарантия, но это не точно.

    Кроме того, операция << для логгирования не очень подходит, т.к. вынуждает использовать конструкции типа:
    oss << "Error: " << strerror(err) << "(" << err << ")";

    для вывода 1 строки. А это уже не одна запись в очередь, а несколько. Так что защита мьютексом тут не будет гарантией вывода целостной строки.
    Для логгера больше подойдет вариант типа std::printf, когда в один вызов передается вся информация для генерации целой строки.
    Ответ написан
    4 комментария
  • Как компилировать общие файлы двух бинарников один раз?

    @res2001
    Developer, ex-admin
    Из файлов исходников, которые используются (или теоретически могут использоваться) в разных целях делаешь статическую библиотеку в рамках этого же проекта.
    В зависимости от размера проекта таких промежуточных библиотек может быть много. Есть смысл сами подобные библиотеки разделять по функционалу. Например в одном тесте тестируется какой-то определенный функционал, в другом - другой функционал и т.п.
    Дальше эту библиотеку(и) ставишь в зависимости для конкретных целей (исполняемый файл, тесты и т.п.)
    Ответ написан
    Комментировать
  • Ошибка в коде C++.?

    @res2001
    Developer, ex-admin
    Кроме указанной компилятором ошибки у вас будет утечка памяти, если 2 раза вызовите set для одного и того же объекта.
    Ответ написан
    Комментировать
  • Правильно ли в C++ использовать директиву препроцессора define?

    @res2001
    Developer, ex-admin
    Помимо define в плюсах есть и другие инструменты.
    Для констант лучше использовать constexpr, для генерации кода шаблоны.
    Для define то же есть своя ниша для использования - тот вариант, что вы привели в примере и т.п.
    В Си кроме define нет ничего другого. В плюсах есть выбор.
    Ответ написан
    Комментировать
  • Как создать структуру с вектором, который хранит экземпляры классов?

    @res2001
    Developer, ex-admin
    В векторе Orderа надо хранить ссылки на Item (или указатели).
    Т.к. дочерние классы Item имеют размер >= sizeof(Item), а в векторе каждый элемент имеет фиксированный размер (сейчас sizeof(Item)), то по сути дочерние классы при попадании в Order обрезаются до состояния Item, а это не то что нужно.
    Ответ написан
    1 комментарий
  • Почему GCC не видит встроенную атомарную операцию?

    @res2001
    Developer, ex-admin
    Почему не использовать функции из стандартной библиотеки?
    https://en.cppreference.com/w/c/atomic/atomic_comp...
    Ответ написан
  • Как исправить ошибку буфера с UART?

    @res2001
    Developer, ex-admin
    Зачем так сложно читаете в read_block?
    Возможно из-за того что у вас возвращаемое ReadFile значение никак не обрабатывается и случаются эти пропуски.
    Если у вас в буфере приема порта что-то лежит - это не значит, что ReadFile гарантированно завершиться синхронно.

    Я бы сделал синхронный ReadFile в цикле с проверкой количества прочитанных байт.
    Учитывая, что и запись и чтение в вашей реализации по сути синхронные, то нет смысла усложнять асинхронщиной.
    Ответ написан