Задать вопрос
Ответы пользователя по тегу C++
  • Как в С++ из INT сделать string16?

    @Mercury13
    Программист на «си с крестами» и не только
    UTF-8 — это многобайтовая кодировка и у неё нет кодов. Так что считаем, что имеем дело с кодами Юникода.
    Это только кусок моей мини-библиотеки, так что…

    Шаблон использовался, чтобы автоматически специализировать под нужную длину wchar_t, реально есть версии под 1 и 2.
    namespace str{
    
    enum {
        SURROGATE_MIN = 0xD800,
        SURROGATE_MAX = 0xDFFF,
        SURROGATE_LO_MIN = SURROGATE_MIN,
        SURROGATE_HI_MIN = 0xDC00,
        SURROGATE_LO_MAX = SURROGATE_HI_MIN - 1,
        SURROGATE_HI_MAX = SURROGATE_MAX,
        UNICODE_MAX = 0x10FFFF,
        U8_1BYTE_MAX = 0x7F,
        U8_2BYTE_MIN = 0x80,
        U8_2BYTE_MAX = 0x7FF,
        U8_3BYTE_MIN = 0x800,
        U8_3BYTE_MAX = 0xFFFF,
        U8_4BYTE_MIN = 0x10000,
        U8_4BYTE_MAX = UNICODE_MAX,
        U16_1WORD_MAX = 0xFFFF,
        U16_2WORD_MIN = 0x10000,
        U16_2WORD_MAX = UNICODE_MAX,
    };
    
    template <int Len>
    void putCpNeT (wchar_t*& p, unsigned long aCp);
    
    ///  Puts a code-point in wchar_t encoding, w/o error-checking
    ///  @param [in,out]  p     position to put to
    ///  @param [in]      aCp   code-point, surely valid
    inline void putCpNe (wchar_t*& p, unsigned long aCp)
        { putCpNeT<sizeof(wchar_t)>(p, aCp); }
    
    } // namespace str
    
    template <>
    void str::putCpNeT<2> (wchar_t*& p, unsigned long aCp)
    {
        if (aCp < U16_2WORD_MIN) {  // 1 word
            *(p++) = static_cast<wchar_t>(aCp);
        } else if (aCp <= U16_2WORD_MAX) {    // 2 words
            aCp -= U16_2WORD_MIN;
            // Hi word
            const wchar_t lo10 = aCp & 0x3FF;
            const wchar_t hi10 = aCp >> 10;
            *(p++) = static_cast<wchar_t>(0xD800 | hi10);
            *(p++) = static_cast<wchar_t>(0xDC00 | lo10);
        }
    }
    
    void str::appendCp(std::wstring& s, unsigned long aCp)
    {
        wchar_t c[5];
        wchar_t* end = c;
        putCpNe(end, aCp);
        s.append(c, end);
    }
    Ответ написан
    Комментировать
  • Можете помочь найти ошибку в коде?

    @Mercury13
    Программист на «си с крестами» и не только
    1. 1/2 = 0, надо писать 1.0/2.0 или просто 0.5.
    2. В printf немного другие правила, чем в scanf, и надо
    printf_s("max = %f\n", max);
    Ответ написан
    Комментировать
  • Может ли код(определение) в заголовочных файлах быть вынесен в shared library?

    @Mercury13
    Программист на «си с крестами» и не только
    Надо сделать CPP-файл, в которые перенести как можно больше кода из программы. И код производят:
    • Static- и глобальные переменные.
    • Нешаблонные, не-inline-функции.
    • Не-inline, полностью расшаблоненные функции template<>.
    • Не-extern объявление шаблона типа template class std::vector<int>.
    Мало того, эти четыре вещи ошибочно держать в хедерах — но этого, как ни странно, в нашей библиотеке и нет, ведь она полностью полагается на шаблоны. Но есть пара резервов.

    1. Функция в теле класса автоматически становится inline, и, я бы сказал, что-нибудь типа AsynchronousReader::init было бы ошибкой держать inline’ом. По-хорошему, его надо в CPP. Но это довольно небольшая часть кода.
    2. Можно также наиболее распространённые версии классов/функций залить в SO. Для этого их надо вынести из тел классов и поступить примерно так.
    // H
    template <int x>
    void foo () { std::cout << x << std::endl; }
    
    extern template void foo<2>();
    
    // CPP
    template void foo<2>();
    Ответ написан
    Комментировать
  • Qt+QMake: как задать настройки компиляции для конкретного файла?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    И снова приходится отвечать самому.

    #pragma GCC optimize("O1")
    #pragma GCC optimize("no-lto")
    Ответ написан
    Комментировать
  • Как посчитать количество совпадающих символов в обоих строках?

    @Mercury13
    Программист на «си с крестами» и не только
    3 тоже есть, так что правильный ответ 3. Ошибка тройная.
    for(size_t z = 0; z < b.length(); z++){
            if(a.find(b[z]) != std::string::npos){

    1. Индексы строк в STL беззнаковые, и компилятор может ругаться на сравнение знакового целого и беззнакового.
    2. На что тут 4, если есть s.length()
    3. Знак «не найдено» — std::string::npos.
    Ответ написан
    3 комментария
  • C++ QT почему не работает запрос к sql Lite DB?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, ваше решение неуниверсально и ваша ошибка — не заэкранировать идентификатор E-mail.
    Попробуйте [E-mail].
    (Часто используется экранирование `E-mail`, но в SqLite оно не катит, это специфика MySQL.)
    Ответ написан
    Комментировать
  • Зачем gcc просит подключить stdlib.h?

    @Mercury13
    Программист на «си с крестами» и не только
    Раз у вас stdlib.h закомментирован, вы, наверно, знаете, откуда malloc взялся. Попробуем раскрутить ошибки.

    note: include ‘ stdlib.h ’ or provide a declaration of ‘malloc’
    Компилятор, очевидно, знает, где этот malloc завалялся…

    warning: implicit declaration of function ‘malloc’ [-Wimplicit-function-declaration]
    …но неявно объявляет функцию.

    warning: incompatible implicit declaration of built-in function ‘malloc’
    Неявное определение int* malloc(int). Реальное void* malloc(size_t). Преобразовать (int*)malloc надо было.

    Почему всё-таки запустилось? А потому, что на целевой машине size_t = unsigned int, а размеры указателей совпадают практически всегда. После того, как функция неявно объявилась, линкер подцепил на её место стандартную, и соглашения вызова совпали.
    Ответ написан
    1 комментарий
  • Header в header'е и можно ли делать игру на одних Header'ах?

    @Mercury13
    Программист на «си с крестами» и не только
    Такой механизм называется «одна единица компиляции» и вполне имеет право на жизнь: на одном процессоре время полной сборки будет наименьшим, потому так распространяют некоторые библиотеки (SqLite, Google Test). Правда,
    игра — обычно масштабный проект, и чем больше будет кода, тем дольше нужно компилировать, чтобы проверить изменения.

    Потому код обычно разбрасывают по единицам компиляции (*.cpp) в соответствии с его внутренней логикой, и к каждой единице (кроме точки входа) приписывают хедер (*.h), который показывает, что эта единица делает. Повторяю, только описывает, что делает — весь код в CPP. И в большинстве случаев самый длинный этап сборки — линковка (особенно с оптимизацией по ходу линковки aka LTO).

    Единственное, что в 80% случаев не получается закинуть в CPP — это шаблоны.

    Чтобы один хедер не подключался несколько раз — есть include guard. Правда, если вы не продумали зависимость между хедерами, может попасться циклическое включение — это вредно, но лишь потому, что программа может не скомпилироваться.

    Чтобы не было циклических включений, для сохранения скорее всего потребуются два хедера: один отвечает за собственно процедуру сохранения и подключается к одному-единственному модулю — системе меню. Второй — за какие-то общие функции, которые позволяют сохраняться в абстрактный поток плиточному фону, снаряду, монстру… Называется как-нибудь SaveUtils.h и подключается повсюду.

    (Примечание. И SqLite, и Google Test разрабатывались по традиционной схеме, с проектом из кучи CPP. SqLite собирается в один большой *.c автоматикой, и я даже качал традиционный код — на 5-метровом файле некоторые версии Embarcadero вылетали с нехваткой памяти. В Google Test есть файл all.cpp или что-то подобное, в котором #include остальных CPP — пользователь подключает в проект all.cpp, и библиотека отнимает минимум его времени.
    Ответ написан
  • Почему Eclipse не подсвечивает тип данных string?

    @Mercury13
    Программист на «си с крестами» и не только
    Главная причина: int — ключевое слово Си++, а string — нет.
    Система программирования может подсвечивать стандартные контейнеры STL другим цветом. Вот, например, скриншот Code::Blocks.
    6cd9ef6d6e4346aaaac0de090af78f88.png
    Видите, ключевое слово char синее, а стандартный объект STL std::string — зелёный.
    (Да, специалисты, вижу, что на экране результат не слишком удачного рефакторинга. Для специализированной утилиты в шестьсот строк, думаю, покатит.)
    Ответ написан
    Комментировать
  • Qt(C++) на windows XP?

    @Mercury13
    Программист на «си с крестами» и не только
    Си++ и Qt сделаны кроссплатформенными, то есть скрывают разницу между платформами где-то у себя внутри.

    Компиляторы перестают поддерживать ту или иную ОС последними. Процессор-то остаётся тем же — ну и норма. Думаю, скомпилированное MinGW (без Qt) даже на 98 запустится.

    Так что разницы не будет, если весь наш софт будет работать на хост-ОС и все наши библиотеки будут запускаться на целевой ОС. А вот с поддержкой беда, версия 5.6 объявлена последней, которая официально поддерживает XP как хост-, и 5.7 — XP как целевую. Работает всё-таки? Вот и классно!

    Да. Раз уж в Qt есть три системы сборки — могут возникнуть вопросы, когда нужно редактировать руками pro-файл. Большинство руководств предполагают QMake. Я держусь на нём, потому что так и не выяснил, как QBS работает с многоядерными процессорами. Двести файлов в проекте — сами понимаете.
    Ответ написан
    Комментировать
  • Как передать counter is for loop внутрь макроса?

    @Mercury13
    Программист на «си с крестами» и не только
    Будет подставлено ИМЯ ПЕРЕМЕННОЙ b, а чему она равна — это уже другой вопрос. Никаких проблем не должно быть.
    #include <iostream>
    
    #define CHECK(a,b) \
       if ((a) == (b))     \
          std::cout << "Equal" << std::endl;  \
          else std::cout << "Inequal" << std::endl;
    
    int main()
    {
        for (int i = 0; i < 5; ++i) {
            CHECK (i, 2)
        }
        return 0;
    }


    После препроцессирования программа превратится вот во что…
    int main()
    {
        for (int i = 0; i < 5; ++i) {
            if ((i) == (2))
               std::cout << "Equal" << std::endl;
               else std::cout << "Inequal" << std::endl;
        }
        return 0;
    }


    Вывод в консоли
    Inequal
    Inequal
    Equal
    Inequal
    Inequal


    Разумеется, нехороши ситуации, когда в макрос подставляется код с побочными эффектами, но это другой вопрос.
    Ответ написан
    1 комментарий
  • Какие задачи решаются на C++?

    @Mercury13
    Программист на «си с крестами» и не только
    На Си++ пишутся сложные быстрые программы. Этим всё сказано.
    Игры, настольные программы, всякие там серверы…

    Лучше скажу, что НЕ пишется на Си++.
    1. Софт, сильно абстрагированный от машины, изменяемый пользователем и/или призванный запускаться где угодно: программы для iOS, Android, веба, высокоуровневые части некоторых игр…
    2. Компактные программы (например, для микроконтроллеров). Сейчас — вотчина Си и его уменьшенных библиотек.
    3. Простые программы, для которых быстродействие и установка дополнительного фреймворка — не проблема: 2D-игры наподобие Braid или Fez, графический редактор Paint.net…
    Ответ написан
    Комментировать
  • Реально ли 2d игра на С++ без граф.библиотек и движокв?

    @Mercury13
    Программист на «си с крестами» и не только
    Без DirectX или OpenGL никуды, это самые низкоуровневые API, дающие как скорость, так и мало-мальскую совместимость.
    Советую использовать тонкую обёртку над всем этим добром вроде SDL: думаю, интереснее будет писать игру, чем решать проблемы с Alt-Tab.
    А так, если задаться целью, можно небольшой движок сделать за неделю-две. Остальное лучше оставить на багофиксы и наполнение.
    Не советую работать с гексами, и вот почему. Гексы сразу же подразумевают, что игра пошаговая. ИИ замучитесь писать!

    И ещё. Систему анимации-то можно за это время написать, но сделать хороший редактор анимаций сложнее. Каждый кадр — отдельная картинка, и всё?
    Ответ написан
    1 комментарий
  • Нарушают ли указатели и разименование в c++ принципы ООП?

    @Mercury13
    Программист на «си с крестами» и не только
    Не будем встревать в холивар «должен ли указатель быть объектом». Примем, что указатель — простейший тип, ради совместимости и эффективности.
    К простейшему типу инкапсуляция и наследование неприменимы.
    А вот для полиморфизма указатели очень нужны. Динамический полиморфизм — это когда под одним фасадом могут оказаться разные объекты.
    1. По копии их передавать невозможно, только по указателю/ссылке.
    2. Их нельзя уничтожать под одну гребёнку. А значит, если мы их передаём в чьё-то другое владение, надо удостовериться, что они созданы в «куче» и у «фасада» есть виртуальный деструктор.

    Есть ещё два принципа ООП — абстракция и принцип Лисков. Первый имеет отношение к указателям постольку, поскольку есть полиморфизм. Второй — гугли «ковариантные/контравариантные указатели».
    Ответ написан
    1 комментарий
  • Как написать структура классов платформера?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Перед нами серьёзный проект: есть и сеть, и подкачка, и поиск путей. Если вы будете писать платформер с нуля, вероятно, «лишние» компоненты вы писать не будете.
    2. Это компоненты, а не классы. Структура классов в геймплее будет более густая, а в рендеринге и физике — менее.
    Например, пишем 2D-рендеринг. Я бы делал Renderer, Tileset, TileLayer, Sprite, Particle…

    В зависимости от желания и целей, лучше воспользуйтесь чужим движком или напишите свой простенький. Куча вопросов отпадёт.
    Ответ написан
    Комментировать
  • Можно ли обновлять модель в Qt по таймингу?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, так нельзя. И вообще, эти части модели вызывает элемент управления (например, QTreeView). Тем чаще, чем активнее мы работаем с данными.

    Как я понял, вы столкнулись с ситуацией: доступ к данным медленный. Значит, надо наладить кэш, чтобы rowCount, parent, index и прочие в большинстве случаев исполнялись мгновенно.

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

    Начнём с того, что синхронизировать поток и UI удобнее всего через сигналы-слоты-emit с типом соединения Qt::QueuedConnection (BlockedQueuedConnection, думаю, многовато будет). У слота будет один параметр: сколько элементов уже подгрузили.

    Для каждого узла, чьих сыновей мы будет подгружать, указываем дополнительное поле: сколько элементов видно из элемента управления. Все сложные структуры данных закрываем мьютексом. Поскольку дело это сложное, для тех объектов, чья ёмкость ограничена и невелика, лучше этого не делать — например, если у нас группы-альбомы-песни, можно делать это только для корневого элемента: даже у продуктивных групп вроде «битлов» элементов не так много.

    В слоте производим такую фишку: rowsAboutToBeInserted, изменяем наше дополнительное поле, rowsInserted. И так для всех элементов, у кого добавилось потомства.
    Ответ написан
    3 комментария
  • Как на 32-битной платформе в переменную типа intptr_t может влезть максимальный адрес ссылки?

    @Mercury13
    Программист на «си с крестами» и не только
    зачем нужно было вообще вводить intptr_t если есть uintptr_t, в который адрес точно влезет?

    intptr_t — разность двух адресов.

    И, более того, как в ЗНАКОВУЮ переменную типа intptr_t можно поместить 32-битный адрес памяти, если в этом числе 1 бит уходит на знак, а для данных остаётся 31 бит?

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

    как может БЕЗЗНАКОВОЕ число равняться числу СО ЗНАКОМ?

    А вот сравнивать их — ошибка, и не зря большинство компиляторов выводит предупреждение. Оба надо перевести либо в unsigned, либо в signed, либо в более крупный знаковый целый тип.
    Ответ написан
    2 комментария
  • Причина работы данного массива структур?

    @Mercury13
    Программист на «си с крестами» и не только
    Таков смысл «си с крестами» — «вы не платите за то, чем не пользуетесь». В данном случае: не пользуетесь авариями — не платите за них. Кстати, самый эффективный способ обработки аварий на x86 только недавно лишился патента, и я не в курсе, есть ли он в MinGW (на x64 патент обошли и он там давно был). Плюс совместимость с Си.

    Правда, мне пришлось сделать свои массивы Array1d и Fix1d именно для того, чтобы проверять границы: включено в debug и выключено в release.
    Ответ написан
    Комментировать
  • Почему в C++ нужно строить всю программу на ООП (длинный вопрос)?

    @Mercury13
    Программист на «си с крестами» и не только
    Задача ООП: 1) Локализовать изменения состояния объекта (инкапсуляция); 2) связывать разные кирпичики данных через стандартные интерфейсы (полиморфизм).

    Простейший тетрис не слишком велик, чтобы его писать на чистом ООП.
    Но представьте себе, мы начинаем налаживать настраиваемое управление джойстиком или клавиатурой. И тогда у нас появляется такой код.
    enum {
      BT_LEFT = 1,
      BT_RIGHT = 2,
      BT_ROTATE = 4,
      BT_SOFTDROP = 8,
      BT_HARDDROP = 16,
      BT_PAUSE = 32,
      BT_CONNECTED = 32768,   // бит, указывающий, что контроллер подключён
    };
    class Controller {  // интерфейс
    public:
      virtual unsigned poll() const = 0;   // сочетание битов BT_XXX
      virtual ~Controller = default;
    };

    Классы Keyboard и Joystick поддерживают интерфейс Controller, и подмена клавиатуры на джойстик и наоборот ничего не изменит.
    Вот вам полиморфизм.

    Текстовый редактор превращаем в многооконный — берём класс Editor и пристраиваем его не к программе в целом, а к MDI-окошку. Вот вам инкапсуляция — локализованное изменение состояния.

    Я как-то мучил движок Doom. Он написан в самом настоящем объектном стиле на чистом Си! Хотя и там были проблемы: сетевой код был куда хуже по качеству, чем сам движок. Писали разделённый экран, глобальную переменную netgame разделили на две, multiplayer и netgame и долго-долго правили баги, где multiplayer, где netgame (было дело, участник десматча ввёл IDKFA, это сработало и вызвало рассинхронизацию). А код пользовательского интерфейса — вообще медвежуть!
    Ответ написан
    Комментировать
  • А как реализуют всякие разархировщики файлов игр для модификаций?

    @Mercury13
    Программист на «си с крестами» и не только
    Сам я бросил ковырять игры давным-давно, и мои знания устарели. Но вот в старых играх, где упаковки ещё не было, я успешно распознавал кое-какие форматы. Но в целом задача состоит из двух: опознание формата архива и опознание формата файла в архиве.

    Архив, как правило, устроен просто (хотя разработчики могут зашифровать его, как в «Мафии»). Разжатие чаще всего делается каким-нибудь из стандартных алгоритмов типа Deflate или LZMA. В принципе, можно и игру дизассемблировать, если алгоритм необычный, но чаще всего нет нужды. Кстати, разжатие из-за того, что оно критично к скорости, не покрывают всякими там Denuvo.

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

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