Ответы пользователя по тегу C++
  • Как создать проект с++ на основе готового кода?

    @Mercury13
    Программист на «си с крестами» и не только
    У меня завелось сразу, хоть и с предупреждениями. Разумеется, проект приходится делать своими силами — и раз уж я использую Qt, сделал вот такой. Прокомментирую его по строчке.
    # Эти четыре строчки Qt установил сам, когда я через интерфейс сказал: нужен проект без Qt.
    # Я только заменил C++11 на 17, едва увидел make_unique.
    TEMPLATE = app
    CONFIG += console c++17
    CONFIG -= app_bundle
    CONFIG -= qt
    
    # Минимальная программа на MinGW требует трёх DLL’ек,
    # и для простоты развёртывания я прикрыл две из них.
    QMAKE_CXXFLAGS += -static-libgcc -static-libstdc++
    QMAKE_LFLAGS += -static-libgcc -static-libstdc++
    
    # Установлено через интерфейс
    SOURCES += \
        olcExampleProgram.cpp
    
    HEADERS += \
        olcPixelGameEngine.h
    
    # Как только дошло до ошибок линкера, я стал смотреть, чего не хватает.
    # А не хватает многого.
    LIBS += -lopengl32 -lgdi32 -lgdiplus -ldwmapi -lshlwapi
    
    # Это третья DLL’ка, которая нужна (была) минимальному проекту на MinGW.
    LIBS += -static -lpthread


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

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    #include <iostream>
    #include <array>
    
    #define consteval constexpr
    
    class Char4
    {
    public:
        using Array = char[5];
        using CppArray = std::array<char, 5>;
        consteval Char4(const char (&x)[5]) : fData { x[0], x[1], x[2], x[3] } {}
        constexpr std::string_view toSv() const { return { fData.asAr, 4 }; }
    private:
        union Ch {
            struct asInts {
                char a, b, c, d;
            };
            char asAr[4];
        } fData;
    };
    
    template <size_t N>
    class CArray4
    {
    public:
        using CppArray = const std::array<Char4, N>;
        constexpr size_t size() const { return N; }
        const Char4& operator [] (size_t i) const { return fBuf[i]; }
    
        template <class ... Args>
        consteval CArray4(Args&& ... x)
            : fBuf { x... }
        {
            static_assert(sizeof...(Args) == N, "CArray size mismatch");
        }
    private:
        CppArray fBuf;
    };
    
    
    namespace {
        CArray4<3> names { "alph", "brav", "char" };
    }
    
    
    int main()
    {
        std::cout << names.size() << std::endl;
        std::cout << names[2].toSv() << std::endl;
        return 0;
    }
    Ответ написан
    Комментировать
  • Что лучше unsigned int или long void?

    @Mercury13
    Программист на «си с крестами» и не только
    Что лучше: сóрок пя́ток или пятóк сорóк? © Винни-Пух
    unsigned int — это тип, поддерживающий положительные числа минимум до 65535 (а в современных реалиях — до 4 млрд)
    long void — нет такого типа в Си++.

    Да, я догадываюсь, вы хотите разницу между unsigned int и unsigned long. Unsigned long поддерживает не менее 4 млрд и в большинстве соглашений соответствует unsigned int (но иногда может давать 1,8·1019 — например, в Unix).

    Если вы пишете под конкретный процессор и конкретную ОС — пишите как угодно.

    Для простейшей кроссплатформенности x86/x64 Windows/Mac/Unix я вообще не рекомендую использовать long, используя int и long long. Для индексов в массиве (и прочего добра, чья длина зависит от длины процессора) используйте size_t и ptrdiff_t.

    Для широкой кроссплатформенности лучше использовать (u)int32_t (если важна арифметика переполнений или точное количество байтов), (u)int_fast32_t, (u)int_least32_t (если важно, чтобы хранило не менее N байтов).
    Ответ написан
    Комментировать
  • Инициализация элемента к нулю?

    @Mercury13
    Программист на «си с крестами» и не только
    1, 3. Просто совпадение, обычно потому, что компиляторы в отладочном режиме всё инициализируют нулями (проще отлаживать). На это нельзя рассчитывать, пиши HWND window = nullptr.
    2. Лучше написать std::string str;, да и всё. Можно рассчитывать, что будет пустая строка.

    Почему 1,3 плохо, а 2 хорошо? Потому что HWND и HRESULT — синонимы для встроенных типов (не то указатель, не то число того же размера), а у них конструктор по умолчанию ничего не делает. А string — нормальный себе объект.
    Ответ написан
    4 комментария
  • Как решить даную проблему?

    @Mercury13
    Программист на «си с крестами» и не только
    Тут всё просто: вы попытались разыменовать NULL-указатель.
    Надо хоть проверить, что наша нестандартная функция (с КиберФорума?) вернула.
    Ответ написан
    Комментировать
  • Почему выполнение программы ускоряется?

    @Mercury13
    Программист на «си с крестами» и не только
    Потому что у вас неэффективный алгоритм вычисления НОД, работающий на вычитании, а не на делении с остатком.
    Естественно, НОД(1,6) = НОД(1, 6−1=5) = НОД(1, 5−1=4) = НОД(1, 4−1=3) = НОД(1, 3−1=2) = НОД(1, 2−1=1) = НОД(1, 1−1=0) = 1
    НОД(2,6) = НОД(2, 6−2=4) = НОД(2, 4−2=2) = НОД(2, 2−2=0) = 2
    С арифметическим переполнением никак не связано. Просто даже в результате переполнения получились немаленькие числа.

    Как надо: НОД(1,6) = НОД(6, 1%6=1) = НОД(1, 6%1=0) = 1
    Аналогично для НОД(6,2) — в общем, сходится довольно быстро.
    Ответ написан
    Комментировать
  • Насколько работает линкер GOLD в MinGW и почему Invalid character?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    В 2021 используйте LLD.
    Ответ написан
    Комментировать
  • Существует ли библиотека Zip с потоковой записью?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    В конце концов перешёл на собственный порт MiniZip.
    Ответ написан
    Комментировать
  • Что означают фигурные скобочки и то что в них написано в векторе с++?

    @Mercury13
    Программист на «си с крестами» и не только
    Это так называемый «универсальный инициализатор» Си++11. Иногда это действительно initializer_list, но не сейчас. Здесь он эквивалентен вызову конструктора
    std::vector<char>(data.get(), data.get() + size)
    Ответ написан
    Комментировать
  • Как выводить переменную в MessageBox?

    @Mercury13
    Программист на «си с крестами» и не только
    Собственно, Александр Ананьев всё сказал.
    А я хочу дополнить.
    1. Вы решили заложиться на компиляцию ANSI/Unicode, но (LPCTSTR)L"Account Details" неправильно сконвертируется в ANSI. Правильно _T("Account Details"). Хотя двадцать два года спустя на компиляцию ANSI, думаю, можно и забить?
    2. MessageBox не предполагает выбора — зачем функции возвращать int?
    Ответ написан
  • Не понимаю задачу, немогу решить,объясните решение?

    @Mercury13
    Программист на «си с крестами» и не только
    Ваш код решает одну задачу, постоянно выводя 38 — и ту через какую-то задницу.
    Во-первых, надо ВВЕСТИ информацию, а не пережёвывать цифры 12 и 126 непонятно каким раком.
    Во-вторых, вам надо получить x = n % 50. Если он 0, то и вывести 0 — иначе вывести 50 − x.
    Ответ написан
    Комментировать
  • Vector - объявление элементов, в чем разница между двумя способами?

    @Mercury13
    Программист на «си с крестами» и не только
    Первый способ: создаётся initializer_list, вызывается конструктор. Наиболее эффективен для простых тупых объектов.

    Второй способ эквивалентен push_back(string("vec1")) и сильно полагается на оптимизацию передаваемых параметров. Наименее эффективен.

    Третий способ гарантированно не создаёт промежуточные объекты (вызывает конструктор string(const char*) уже на месте). Вместе с reserve(3) наиболее эффективен для управляемых объектов.

    UPD. 2 и 3 для string() не очень сильно различаются из-за эффективного переноса. А вот для более крупных объектов 3 лучше.

    UPD2. Начиная с Си++20, 1 лучше, но только из-за того, что Си++ научился делать полноценные string’и при компиляции — то есть управляемый объект string обзавёлся некоторыми чертами тупого.

    UPD3. Ни один компилятор пока constexpr string пока не поддерживает. Но ведь ни у кого стабильного 20 пока нет, правильно?
    Ответ написан
    9 комментариев
  • Как создать изображение из массива uint8_t?

    @Mercury13
    Программист на «си с крестами» и не только
    Дело не в этом. Массив 16·8 (вместо 32×32) и такая картинка — вероятно, формат 1-битный.
    Попробуйте Format_Mono или Format_MonoLSB.
    Ответ написан
  • Как переписать данный код?

    @Mercury13
    Программист на «си с крестами» и не только
    Я бы предложил поискать в коде ошибку, есть большое подозрение — первым множителем так и просится size. Ну или деление size %/ msize — невозможно сказать. Ну или условием будет не меньше, а больше или больше-равно. Но будем работать как есть.

    int v = msize / size;
    if (i < msize % size) ++v;
    int teqportion = msize * v;


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

    @Mercury13
    Программист на «си с крестами» и не только
    1. Op= излишня, такая конструкция сама себя присвоит. С деструктором аналогично.
    2. Op+ — лучше пользоваться исключениями.
    3. Странное у вас устройство матриц — и не совсем константные, и менять нельзя.
    4. A[i][j] = i; — возможен выход за пределы массива.
    5. Если вывод матриц многострочный — подобный вывод не слишком удачный.
    Ответ написан
    Комментировать
  • Аргумент типа char не совместим с параметром типа const char*. Как исправить?

    @Mercury13
    Программист на «си с крестами» и не только
    Если вы узнали, что символ — цифра, просто вычтите из него '0'.
    meow[i] = gug[i] - '0';

    if (digit == true) не рекомендую писать, надо просто if (digit).
    Ответ написан
    Комментировать
  • Как декодировать UTF-16 на С++?

    @Mercury13
    Программист на «си с крестами» и не только
    Это не Паскаль, это типизированный Бейсик.
    Вот мой рабочий код — каждый вызов читает одну кодовую позицию, перемещая первый указатель на нужное кол-во слов вперёд. Переведёшь в нужные тебе соглашения по работе? — например, ты можешь читать информацию не из памяти, а из файла или ещё откуда-то.
    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,
    };
    
    #define CHAR_BOM L'\uFEFF'
    
    #define UNICODE_NONE (0xFFFFFFFFUL)
    #define UNICODE_BAD  (0xFFFFFFFEUL)
    
    unsigned long str::getCp(const uint16_t*& aCurr, const uint16_t* aEnd)
    {
        if (aCurr == aEnd)
            return UNICODE_NONE;
        unsigned long cp = *(aCurr++);
        if (cp < SURROGATE_HI_MIN) {
            if (cp < SURROGATE_MIN) { // Low BMP char => OK
                return cp;
            } else {  // Leading surrogate
                if (aCurr == aEnd)
                    return UNICODE_BAD;
                unsigned long trailing = *aCurr;
                if (trailing < SURROGATE_HI_MIN || trailing > SURROGATE_HI_MAX)
                    return UNICODE_BAD;
                ++aCurr;
                return (((cp & 0x3FF) << 10) | (trailing & 0x3FF)) + 0x10000;
            }
        } else {
            if (cp <= SURROGATE_MAX) { // Trailing surrogate
                return UNICODE_BAD;
            } else { // High BMP char => OK
                return cp;
            }
        }
    }


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

    Алгоритм: читаем слово. Двумя сравнениями относим его к одному из четырёх диапазонов: 1) нижний диапазон базовой плоскости, 2) нижний суррогатный символ; 3) верхний суррогатный символ; 4) верхний диапазон базовой плоскости. Если 1 или 4, так его и возвращаем, если 3 — видим херню.

    Если же 2, считываем слово, не смещая каретки. Если слово не верхний суррогатный символ — херня. В противном случае смещаем каретку и собираем номер кодовой позиции.
    Ответ написан
    Комментировать
  • Не могу понять принцип округления float point, объясните на примере цифры?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Округление к чётному. Это стандартное округление к ближайшему; если расстояние одинаково — то к чётному.
    4,4 → 4
    4,5 → 4
    4,6 → 5
    −4,4 → −4
    −4,5 → −4
    −4,6 → −5
    5,4 → 5
    5,5 → 6
    5,6 → 6
    −5,4 → −5
    −5,5 → −6
    −5,6 → −6

    2. Округление вниз к −∞. Округление к меньшему.
    4,xxx → 4 (при любой дробной части)
    −4,xxx → −5

    3. Округление вверх к +∞. Округление к бóльшему.
    4,xxx → 5
    −4,xxx → −4

    4. Отбрасывание дробной части. Округление к 0. Округление к меньшему по модулю.
    4,xxx → 4
    −4,xxx → −4

    Столько много знаков у double — так что где-то в недрах библиотеки float стал double’ом. Знаков у float не точно 7, а чуть больше семи. И это число действительно не тройка: тройка имеет 16-й вид 4040.0000, а ваше число — 403F.FFFF. Как вы видите, величина единицы младшего разряда (ULP) на таких величинах будет около 2,4·10−7 — поболее семи знаков будет, но до восьми не дотягивает.

    Механизмы округления IEEE 754 не имеют никакого отношения к десятичному округлению, прописанному в библиотеке языка. Округление IEEE на самом деле двоичное и используется при переводе из более точного типа в менее точный, или чтобы округлить результат умножения/деления.
    Ответ написан
    Комментировать
  • Какая разница между спецификатором, модификатором, квалификатором, идентификатором, инициализатором?

    @Mercury13
    Программист на «си с крестами» и не только
    Спецификаторы определения — слова typedef, inline, friend, constexpr, constinit, register, static, thread_local, extern, mutable.
    Спецификаторы типа — что угодно, что полностью определяет тип: начиная от int и заканчивая vector<int>::const_iterator.
    Модификаторы типа — слова short, long, signed, unsigned.
    Квалификаторы — слова const, volatile.
    Спецификаторы доступа — слова private, protected, public.
    Идентификатор — имя объекта, подчиняющееся определённым правилам.
    Объявитель — это часть объявления переменной или функции, и если ты не лезешь с головой в тонкости синтаксиса Си, тебе не надо.
    Инициализатор — это int i = 1 или int i {1}.
    Ответ написан
    2 комментария