Ответы пользователя по тегу C++
  • 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.

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

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

    @Mercury13
    Программист на «си с крестами» и не только
    В 99,9% случаев — на языках высокого уровня. Как слой более низкого уровня используются три вещи.
    1. Стандартная библиотека языка.
    2. Внутреннее API ОС (WinAPI/POSIX/DOS).
    3. Чужие низкоуровневые библиотеки.

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

    Здесь под «низким уровнем» понимается «мало автоматизации», «очень тонкая прослойка между API операционной системы и нашим новым интерфейсом», «минимум управления памятью» — то есть функция, например, принимает не std::string, а указатель на нуль-терминированную строку const char*. И для написания библиотек любят языки, способные работать на низком уровне — в первую очередь Си, Си++ и Паскаль. Если нет ограничения по скорости, ассемблер не обязателен.
    Ответ написан
    1 комментарий
  • Как открыть порт на роутере? Комплексное решение?

    @Mercury13
    Программист на «си с крестами» и не только
    1. https://portforward.com/tp-link/tl-wr740n/
    www.pcwintech.com/port-forwarding-tp-link-tl-wr740...
    forum.tp-linkru.ru/viewtopic.php?t=9
    Но не забывайте, что это требует статического IP-адреса сервера, и лучше всего это сделать, прописав статическую зависимость MAC-IP. По третьей сцылке это есть.
    2. Гуглите UPnP. Посмотрите, допустим, вот. Использование UPnP C++
    3. Сам даже не знаю. Как-то само из кусочков понимание собралось. Правда, я в своё время налаживал локальные «сети» по COM- и LPT-кабелю. А потом по-чёрному резался в разные игры по интернету. Разумеется, тонкостей настройки больших сетей мне это не дало, но как ходят пакеты, примерно понимаю.
    Ответ написан
    2 комментария
  • При завершении работы программы падает исключение, что делать?

    @Mercury13
    Программист на «си с крестами» и не только
    Это испорченная память, где-то ошибка в управлении памятью (например, запись за границами массива).
    UPD. Ваша ошибка: в составе std::string есть внутренние неконтролируемые поля, и его нельзя побайтово сохранять в файл. Такими неконтролируемыми полями могут быть указатели, кэши-ускорители и многое другое. Вообще std::string состоит из указателя или двух, и отсюда следуют две вещи. 1) При сохранении в файл не попадут строковые данные, попадёт только указатель. К тому же в Windows нет хорошего 16-ричного просмотрщика, а без него при работе с файлами как без рук (по крайней мере начинающему, я давно обхожусь). 2) Как только вы этот указатель загрузите, std::string портится, и на деструкторе может случиться что угодно.

    Вам надо самим придумать формат файла и реализовать загрузку/сохранение, используя length(), data() и front().

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

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

    Что ещё пока вижу (но это не причина ошибки).
    1.
    unsigned short int *exam_t = new unsigned short int[5];
    Нет нужды new, невелик массив. Хватает локального массива на стеке. Аналогично остальные два new.
    2. Нет нужды давать clear/close. Это фишка Си++, автоматически сработает деструктор.
    3. Не называйте переменную flag, называйте wasFound (или что она реально значит).
    4. sizeof(&student_r) только чудом совпадает с sizeof(student_r).
    5. Не надо писать flag == false, надо !flag.
    6. Функция del_reversive делает излишнюю работу и переставляет студентов, к тому же есть стандартный алгоритм remove_if.
    7. while (!flag) в del_rev бессмысленно.
    8. Вы же работаете со string’ами — зачем вводить информацию в буфер ограниченной длины?
    9. Программа не модульная, нет нужды в хедере.
    Ответ написан
    Комментировать