Ответы пользователя по тегу C++
  • Как подключить файл во время работы программы?

    @Mercury13
    Программист на «си с крестами» и не только
    Что значит «подключить файл»?
    Загрузить файл данных? std::ifstream.
    Загрузить динамическую библиотеку? Ищи системные функции вроде LoadLibrary в Windows и dlopen в Linux. (Кроссплатформенных библиотек загрузки DLL/SO мало, а стандарт за этим даже не гонялся.) Но в любом случае потребуются заголовки функций в препроцессорном файле.

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

    Файл исходника подключается не препроцессором, а системой сборки (потому что так работал ассемблер, и потому что разделение компилятора, линкера и системы сборки позволяет соединять вместе код, написанный на разных языках, и потому что хорошая система сборки позволяет включать в сборку нестандартные шаги). Да, существует устройство кода «одна единица трансляции» — у неё кратчайшее время полной перекомпиляции, но невозможна компиляция по частям и на многих процессорах, и одну единицу обычно берут для среднего размера библиотек (SqLite), где-то до минуты — время немалое, но любая значимая программа перебьёт, и один хрен библиотеку пересобирают только целиком. Препроцессором обычно подключаются заголовки типов и функций.

    Если нужна поддержка скриптов в проге — смотри на Lua. В последнее время очень любят Python. но я не в курсе и один хрен пригодно только для больших прог, готовых таскать с собой дистрибутив Питона.
    Ответ написан
  • Какая сложность у std::sort?

    @Mercury13
    Программист на «си с крестами» и не только
    Символ Ландау g(x) = O(f(x)) при x→y означает: g(x)⩽kf(x) при x, достаточно близких к y. В данном случае y=∞.
    То есть с точностью до константы. А как Wataru сказал, основание логарифма — это умножить на константу.

    А я попытаюсь сказать, почему удобны символы Ландау.
    1. Математическим исследованием сложно выяснить, сколько операций займёт одна итерация цикла — две или тысячу. Этим пусть занимаются микрооптимизации.
    2. Зато в любую программу загонят столько данных, что она сломается. И как правило — если не доказано обратное — асимптотическая сложность быстро пересилит эту самую константу, и программа большей сложности сломается первой.
    3. Ну вот прога сломалась, и мы занялись микрооптимизациями и заменили процессор, и получилось, скажем, вдвое — насколько более крупные задачи мы теперь можем решать? Если O(N), то вдвое более крупные. Если O(N log N), то несколько меньшие, чем вдвое. А если O(N²), то в 1,4 раза.
    Ответ написан
  • Как написать что-то в консоли?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак, надо вызвать прогу и повзаимодействовать с ней. Кроссплатформенность нужна?

    Если работаем на чистом WinAPI, надо пробовать перенаправление потоков ввода-вывода.

    С повышением прав не работал: если повышение не нужно, или прога изначально работает под одминком, никаких вопросов, но ведь всякое бывает…
    Ответ написан
    Комментировать
  • Отличие int32_t от std::int32_t?

    @Mercury13
    Программист на «си с крестами» и не только
    Никакого. int32_t — это из Си, std::int32_t — стандартное пространство имён Си++.
    Ответ написан
    Комментировать
  • Почему появляется лишний символ при открытии файла qt C++?

    @Mercury13
    Программист на «си с крестами» и не только
    А какой код генерации этих данных? Я пока вижу, что 8 байтов длины в формате Motorola (58), после этого 58 байтов данных. Мне интересно узнать, откуда взялся qword длины, и откуда — dword 6 в начале, тоже в формате Motorola?

    UPD. Пока подозреваю, что дело в SendBufferSizeSocketOption.
    Ответ написан
  • Почему имя параметра может совпадать с именем члена класса?

    @Mercury13
    Программист на «си с крестами» и не только
    Это НЕ синтаксический разбор, а семантика языка.
    В большинстве случаев играет роль ближайший идентификатор. Но в инициализаторах снаружи скобок поле объекта (больше ничего там быть не может, только поле)

    #include <iostream>
    
    class Obj {
    public:
        Obj(std::string x)
            : x(std::move(x))
            // 1. Поле, больше ничего быть не может
            // 2. Параметр, как ближайший идентификатор
        {
            std::cout << '[' << x << ']' << '\n';  // Параметр, как ближайший идентификатор
        }
    private:
        std::string x;
    };
    
    int main()
    {
        Obj obj("Habr");
        return 0;
    }
    Ответ написан
  • Как генерировать случайные числа в вычислительной системе?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак, задача — сгенерировать случайные числа по закону Гаусса.
    Если есть Си++11, копай модуль <random>.
    Если нет, простейший способ сгенерировать — F⁻¹(ξ), для этого есть бэ-мэ качественные приближения обратного распределения Гаусса.
    Есть также более «лёгкий» способ генерировать такие числа по два сразу, гугли.
    Ответ написан
    Комментировать
  • Как вшить .mp4 файл в .exe С++?

    @Mercury13
    Программист на «си с крестами» и не только
    На данный момент вы вызываете внешний плеер, причём не важно, какой — системный ассоциированный с расширением MP4. Не забудьте, что в такой ситуации внешнего плеера уже не будет, придётся налаживать свой.

    1. ОС-зависимые ресурсы (например, ресурсы Windows). Поскольку тут у вас и так WinAPI, этот способ вполне катит.
    2. Обёртка Qt или чего-то другого над этими ресурсами: где они есть, ресурсы, а где нет, простые массивы. Использовать, если и без того используете Qt.
    3. Склеить EXE-файл с MP4. Главное — придумать способ разделить их обратно (например, добавить четыре байта длины в конце).
    4. Преобразовать MP4 в байтовый массив, вставить в какой-то CPP.
    5. Вариант 4, но более быстрый в компиляции: Использовать ожидаемую функцию Си #embed.
    Ответ написан
    Комментировать
  • Как переделать код согласно современным стандартам?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы с неинициализированной памятью работаете почти правильно, но…

    Первое. Надо указать выравнивание класса.
    MyClass* arr = (MyClass*) operator new (sizeof(MyClass) * 10,
                                            std::align_val_t(alignof(MyClass)));
    . . .
    operator delete(arr, std::align_val_t(alignof(MyClass)));


    Второе. А нельзя инкапсулировать подобную работу с памятью в класс, чтобы конструктор выделял память и деструктор отдавал? Я сделал вот такое.
    #include <iostream>
    
    class MyClass {
    private:
        const int a;
    public:
        MyClass() = delete;
        MyClass(MyClass&&) = delete;
        MyClass(const MyClass&) = delete;
        MyClass(int a) : a(a) {};
        ~MyClass() = default;
        MyClass& operator=(MyClass&&) = delete;
        MyClass& operator=(const MyClass&) = delete;
        operator int() const { return a; }
    };
    
    template <class T>
    class DynArray {
    public:
        static constexpr std::align_val_t ALIGNMENT { alignof(T) };
        DynArray (size_t n)
            : maxSize(n),
              d((T*) operator new (sizeof(T) * n, ALIGNMENT )) {}
        ~DynArray() {
            std::destroy_n(d, currSize);
            operator delete(d, ALIGNMENT);
        }
        template <class... Args>
            T& add(Args&&... args);
        T& operator [] (size_t i) { return d[i]; }
        const T& operator [] (size_t i) const { return d[i]; }
    private:
        size_t currSize = 0, maxSize = 0;
        T* d;
    };
    
    template <class T> template <class... Args>
    T& DynArray<T>::add(Args&&... args)
    {
        if (currSize >= maxSize)
            throw std::logic_error("[DynArray::add] Overflow");
        auto& where = d[currSize++];
        new (&where) MyClass(std::forward<Args>(args)...);
        return where;
    }
    
    int main() {
        DynArray<MyClass> da(10);
    
        for (int i = 0; i < 10; ++i) {
            da.add(i);
        }
    
        // Что-то сделали с массивом
        for (int i = 0; i < 10; ++i) {
            std::cout << da[i] << '\n';
        }
    
        return 0;
    }


    Ну и третье — в коде есть, но забыл указать — разбирайте API неинициализированной памяти Си++17.

    ЧЕТВЁРТОЕ. Есть один класс, который не перемещает. Поскольку начиная с Си++17 весь STL внутри работает с неинициализированной памятью, получается довольно мило — но хранится ли оно непрерывно, мы никак не узнаем.
    std::deque<MyClass> dq;
        for (int i = 0; i < 10; ++i) {
            dq.emplace_back(i + 42);
        }
        // Что-то сделали с массивом
        for (int i = 0; i < 10; ++i) {
            std::cout << dq[i] << '\n';
        }
    Ответ написан
    2 комментария
  • Почему переменная становится равна 1, если после инициализации класса она была равна 3?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы используете одноимённую локальную переменную в MainProgram().
    MainProgram::m_command_file_len должно равняться нулю ЧЕМУ ПОПАЛО, потому что его никто не трогал.

    UPD. Вы ещё и неправильно используете венгерскую нотацию: префикс f, m или _, оставленный для внутренних переменных, почему-то забрался в локальную.
    Ответ написан
    1 комментарий
  • Как сделать чтоб перснаж не мог проходить через стены?

    @Mercury13
    Программист на «си с крестами» и не только
    Если отбросить в сторону общую упоротость кода (облом делать ревизию), проблема вот в чём.
    Работая с коллайдером (фигурой, которая участвует в проверке столкновений, она же хитбокс), вы выбрали диапазон клеток
    [y / 16; (y + h) / 16).

    Например, y = 1, h = 16, (y+h)/16 = 1, диапозон [0,1), и проверяется только клетка 0. А надо 0 и 1.

    Так что надо [y / 16; (y + h - 1) / 16]. ВКЛЮЧАЯ СПРАВА.
    Ответ написан
    Комментировать
  • Как сделать чтоб одна вункция роботала всегда а другая паралельно каждую секунду?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак.
    1. В играх очень хорош объектный подход — что-то вроде
    class World {
    public:
      bool wasStarPlaced = false;
      bool wasStaircasePlaced = false;
      std::vector<std::vector<char>> map;
      unsigned long long tick = 0;  // пригодится ещё
      void update();  // стандартное название для функции «исполнить игровой такт»
    };

    Тут даже не нужны все каноны ООП, достаточно что-то вроде «поле X принадлежит объекту Y».

    2. Многопоточка чревата гонками по данным, и если в многопоточку не стоит — пожалуйста, не делайте! В данном случае вы хотите что-то вроде: каждую секунду выполнять дополнительную ветку.

    Как я понял, игра динамичная, и расчёты в ней достаточно простые, чтобы вести их с постоянной частотой (например, 60 тактов/с).
    constexpr int TICKS_PER_SEC = 60;
    
    void World::update()
    {
      ++tick;
      if (tick % TICKS_PER_SEC == 0) {
         // происходит каждые 60 тактов
      }
    }
    Ответ написан
    Комментировать
  • Как обеспечивается совместимость динамических библиотек при ликовке в рантайме?

    @Mercury13
    Программист на «си с крестами» и не только
    Устроено просто.
    1. Имена всё равно стараются не козявить. Те библиотеки, где объектный интерфейс выставлен наружу, менее любимы. А уж шаблонных специализаций вообще сторонятся.
    2. А если козявить — есть модель Windows (MSVC, Borland) и модель Linux (MinGW, CLang).
    3. В модели Linux подключение DLL устроено через файл *.a, смысл которого для DLL’ки — сопоставить покозявленное компилятором имя функции и таковое же, выставленное DLL’кой наружу. И для любой DLL’ки можно создать этот *.a с любыми именами. MSVC CL и MinGW LD могут подключать DLL и напрямую, CLang LLD — когда проверял, ещё нет.
    4. Да, а как заменить в скомпилированной программе. Обычно новую версию DLL’ки компилируют тем же компилятором — вот и вся совместимость. В x64 с этим делом проще, чем в x86 — меньше соглашений вызова.
    5. Часто в ABI приходится переименовывать функции из-за того, что сменилась сигнатура. То есть тащат и старую, и новую с разными именами.

    Когда программа собирается одним компилятором, а DLL’ка другим — это всегда большая сложность, и вопроса два: соглашения вызова и правило, по которым козявятся имена.
    Ответ написан
    Комментировать
  • В какого типа переменных хранить адреса?

    @Mercury13
    Программист на «си с крестами» и не только
    Вариантов много.
    1. Непрозрачные указатели, которые нельзя разыменовывать.
    struct OpaqueAddress;
    using Address = OpaqueAddress*;

    2. void*, const void*.
    3. uintptr_t.
    4. Жёсткие int’ы, если работаем с конкретной посторонней прогой под конкретную архитектуру (например, пишем чит к игре).
    using Address = uint32_t;
    5. Enum class, основанный на соответствующем int’е.
    enum class Address : uintptr_t { NUL = 0 };
    Ответ написан
    Комментировать
  • Что стоит учить с или c++ или c#?

    @Mercury13
    Программист на «си с крестами» и не только
    Если ты умеешь программировать на чём угодно, хоть на Скрэтче — можно любой по желанию. Разберёшься.
    Если с нуля — только C#, на нём меньше шансов напортачить. Главная проблема Си, плохо решённая в Си++,— для простых вещей приходится работать со сложными концепциями вроде указателей для scanf.
    Ответ написан
    Комментировать
  • Почему '\xDA', '\xc4', и другие управляющие последовательности не работают?

    @Mercury13
    Программист на «си с крестами» и не только
    Потому что вы перевели консоль в кодировку Win-1251 и и ждёте в ней псевдографику.
    Лучше всего работать в каком-то из вариантов Юникода.
    Ответ написан
    Комментировать
  • Как нормализовать массив значений в цветовое представление?

    @Mercury13
    Программист на «си с крестами» и не только
    Уровень 1. Чёрно-белое.
    R, G, B = round((x−min)·255 / (max − min))

    Уровень 2. Градиент между цветом X и цветом Y.
    t = (x−min) / (max − min)
    R = round(R1·t + R2·(1−t))
    G и B аналогично.

    Уровень 3. Учёт гамма-кривой монитора. Тут работаем сразу в двух цветовых пространствах: линейном от 0 до 1, и sRGB от 0 до 255.
    gamma = 2,2 — sRGB состоит из линейного и степенного участка, но неплохо приближается real_brightness = channel_%^gamma
    invGamma = 1/gamma
    функция toLinear(v) := (v/255)^gamma
    функция toSrgb(q) := (q^invGamma)·255 — в общем, обратная
    linR1 = toLinear(R1)
    linR2 = toLinear(R2)
    t = (x−min) / (max − min)
    R = round(toSrgb(linR1·t + linR2·(1−t)))

    Уровень 3.1. 16-битная аппроксимация (если важна скорость). В общем, линейное цветовое пространство — не дробные от 0 до 1, а целые от 0 до 65535.
    функция toLinear(i) := round(((i/255)^gamma)·65535)
    массив toSrgb(q) := ((q/65535)^invGamma)·255 — записывается в виде массива на 65536 величин
    linR1 = toLinear(R1)
    linR2 = toLinear(R2)
    K = (65535 / (max − min)
    t = round((x−min) * K)
    R = toSrgb(((linR1·t) + linR2·(65535−t) + 127) >> 16)

    Уровень 4. Сложный градиент из нескольких цветов.
    Для этого например, t=0 — синий, t=⅓ — зелёный, t=⅔ — жёлтый, t=1 — красный.
    Тогда прикидываем, в какой промежуток попадает t, получаем, например, t1=(t−⅓)·3, и дальше по уровню 3.
    Ответ написан
    Комментировать
  • Мне надо иметь две .lib для debug и release?

    @Mercury13
    Программист на «си с крестами» и не только
    Debug-версия библиотеки может помочь отлаживать какую-то дичь на границе вашего и библиотечного кода. Я лично не пользовался ни разу, всюду подключал release-версию.
    UPD. Я не работал с MSVC, но этот самый MSVC имеет разные runtime-библиотеки для отладки и выпуска. И они не хотят соседствовать друг с другом. Это уже внутренние разборки MSVC; две библиотеки MinGW, статическую и динамическую, но обе release, вполне себе позволяет и для некоторых целей (упрощение отладки на той самой границе) очень даже помогает. SDL2, как и большинство открытых библиотек, имеют минимальные зависимости и ему просто не нужна библиотека MSVC.
    Ответ написан
    Комментировать
  • В чем ошибка блок-схемы?

    @Mercury13
    Программист на «си с крестами» и не только
    Если считать, что прога верная, а блок-схема нет.

    1. Непонятно, почему ввода нет, вывод есть.
    2. Начальное присваивание smallest опущено.
    3. Очень креативно изображён двойной цикл. Не знаю, верно ли это — но пару вложенных циклов, если рамки внутреннего не зависят от того, что творится во внешнем и не нужно прерывать один внутренний, я бы написал оба в одном шестиугольнике.
    4. Условие внутреннего цикла я бы написал i=[0..n)
    5. В программе сначала выводим сообщение, потом матрицу. На БС наоборот.

    PS. Чёртов препод, ну не годится тут блок-схема, и точка. Может, она больше годилась, когда не было структурного программирования…
    Ответ написан
    Комментировать
  • Как правильно округлять числа с плавающей точкой с заданной точностью?

    @Mercury13
    Программист на «си с крестами» и не только
    Гуглите GRISU2 — и, возможно, переделайте этот код под свои нужды.
    Он работает на целой арифметике и делает вот что: находит самое круглое десятичное число, переводимое в компьютерное дробное x.

    Допустим, мне приходилось добавлять такое.
    1. В случае не очень большого числа, большего 1/относительная_погрешность — поднять точность до единиц.
    Например, переходить в экспоненциальный формат, когда у нас больше 5 цифр, а точность 3 цифры — то 0,00123, 0,0123, 0,123, 1,23, 12,3, 123, 1234, 12345, 1,23e5.

    2. Большее из абсолютной и относительной погрешности.
    Если у нас ещё две цифры абсолютной погрешности — то 0, 0,01, 0,12, 1,23, 12,3…

    3. Формат с фиксированной длиной дробной части по принципу «всё или ничего».
    С теми же двумя цифрами абсолютной погрешности — 0, 0,01, 0,12, 1,23, 12,34, 123…

    4. Работу с локалями.
    Ответ написан
    Комментировать