Ответы пользователя по тегу C++
  • Как декодировать 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 комментария
  • Как отсортировать вектор по одному из элементов структуры?

    @Mercury13
    Программист на «си с крестами» и не только
    std::sort(thrusters.begin(), thrusters.end(), 
        [](const calcThrusterType& x, const calcThrusterType& y) {
            return (x.angle < y.angle);
        });

    Вы используете typedef и в вашем компиляторе нет Си++11?
    bool angleLess(const cTT& x, const cTT& y) { return x.angle < y.angle; }
    
    std::sort(thrusters.begin(), thrusters.end(), angleLess);
    Ответ написан
    1 комментарий
  • Где у меня может быть ошибка в нахождении площади сложной фигуры?

    @Mercury13
    Программист на «си с крестами» и не только
    Обсуждение было в комментах, и ключевая причина — при comp_a < 0 корни не сортируются.

    Побочные проблемы кода.
    1. Можно было интеграл разности, а не разность интегралов.
    2. Лучше не использовать vector и pair на месте struct { a, b, c } — кроме случаев, когда есть важная автоматизация.
    Ответ написан
    Комментировать
  • Как ускорить решение на c++?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы тут что-то ухитрились написать, но всё равно n². Потому и TL.

    Пусть для каждого поддона длина — большее из измерений, ширина — меньшее. Теперь условие «поддон А можно поставить на поддон Б» упрощается.

    Очевидно, что поддоны, которые нельзя поставить друг на друга, будут возрастать по одному измерению и убывать по другому. (Иначе мы сортанём по длине, по ширине тоже обнаруживаем неубывание — и, сюрприз, эти поддоны становятся!)

    Получаем список поддонов, которые не становятся ни на кого. Проще всего хранить его в виде set с сортировкой по длине, при этом ширина убывает.

    Нам приходит новый поддон. Упорядочиваем координаты, затем ищем в списке equal_range по длине.

    Для «БОЛЬШЕЙ» части списка [LOWER_bound, end): наш поддон можно поставить на все эти поддоны по длине, и только на первые из них — по ширине. Если l_b=end, или наш поддон не встаёт на *l_b — добавляем поддон в список. Но не сразу, а после проверки меньшей части.

    Для «МЕНЬШЕЙ» части списка [begin, UPPER_bound): все эти поддоны можно поставить на наш поддон по ДЛИНЕ, и только некоторый хвост [some_pallet, upper_bound) — по ширине. Находим этот кусок и исключаем из дерева.

    А теперь вопрос: как хакнуть наш set, чтобы можно было проводить поиск за log n и по длине, и по ширине?
    А для этого пишем свой объект-сравниватель, который можно переключать между двумя вариантами: length1<length2, либо width1>width2;

    P.S. Не очень понятно условие «один поддон становится на другой» — ни из описания, ни из примера. Мой алгоритм — length1 <= length2, width1 <= width2. Если, например, оба строго меньше (length1 < length2, width1 < width2) — то большая часть будет [u_b, end), меньшая — [begin, l_b), и из-за непересечения этих частей не обязательно добавлять в список отложенно.
    Ответ написан
    7 комментариев
  • Как перенести структуру в бинарный файл что бы он мог его прочитать без повреждения файла?

    @Mercury13
    Программист на «си с крестами» и не только
    Начнём с 2. Структуры, используемые как формат файла, применяй в прикладном коде с большой осторожностью. Если хочешь, чтобы формат расширялся, придумай простенький блочный формат.
    Для 1 — приходится использовать какую-то сигнатуру и находить её в файле.
    Например: после собственно EXE-файла идут данные, потом сигнатура и положение данных в файле. Сигнатуры нет или смещение странное — значит, просто приклеивай всю эту дрянь в конец файла. Сигнатура есть и смещение правдоподобное — идём по указанному смещению, пишем новые данные вместе с новой сигнатурой, а потом усекаем файл (на случай, если старые данные были длиннее).
    На этом принципе, кстати, основаны самоизвлекающиеся архивы RAR и RARJPEG — только сигнатура в начале, а не в конце RAR-данных.
    Ещё нужно проверить, в какой кодировке ifstream принимает данные — UTF-8 или Win-1251. Начиная с Си++17 появилась поддержка юникодных имён файлов, но я с нею не работал.
    Ответ написан
  • Как сделать срез массива?

    @Mercury13
    Программист на «си с крестами» и не только
    В Си++ нет понятия «произвольный массив», и это мешает.
    Но несложно этот самый произвольный массив (без хранения) написать
    template <class T>
    struct Buf1d {
      size_t size;
      T* d;
      constexpr Buf1d() : size(0), d(nullptr) {}
      constexpr Buf1d(size_t aSize, T* aD) : size(aSize), d(aD) {}
      Buf1d(std::vector<T>& x) : size(x.size()), d(x.data()) {}
    }

    И этому Buf1d можно придумать и другие функции, например:
    template <class T>
    Buf1d<T> Buf1d<T>::sliceLeft(size_t x) const
    {
      if (x >= size) {
        return {};
      } else {
        return { size - x, d + x };
      }
    }


    Если же вам нужно с хранением, то, например, можно воспользоваться старым добрым vector.
    template<class T>
    std::vector<T> sliceLeft(const std::vector<T>& v, size_t x)
    {
      if (x >= v.size()) {
        return {};
      } else {
        std::vector<T> r;
        r.insert(r.end(); v.begin() + x, v.end());
        return r;
      }
    }
    Ответ написан
  • Какую программу можно сделать с использованием двумерного массива?

    @Mercury13
    Программист на «си с крестами» и не только
    Тетрис. Питончик. Морской бой.
    Ответ написан
    Комментировать
  • Что значит const volatile?

    @Mercury13
    Программист на «си с крестами» и не только
    const — чтобы исключить попытки писать в него.
    volatile — каждый раз при обращении проходить по адресу и брать данные , а не кэшировать.
    Если какая-то ячейка в памяти (в данном случае по адресу 0x30) меняется другим потоком или, например, железом, она volatile.
    Лучше было бы писать
    const volatile char* const port = (const volatile char *) 0x30;

    Ещё лучше (Си++11 и непортабельно)
    constexpr const volatile char *port = (const volatile char *) 0x30;

    А ещё лучше сделал Паскаль
    var
      SomePort : byte absolute $30;
    Ответ написан
  • Ошибка с типами с++?

    @Mercury13
    Программист на «си с крестами» и не только
    1. C:\Users\XXX\Desktop — не обязательно стол будет там.
    2. Гуглите функцию std::string::c_str() — преобразование string в нуль-терминированную строку Си.
    Ответ написан
    Комментировать
  • Что означает данная запись структуры?

    @Mercury13
    Программист на «си с крестами» и не только
    Переменная этого типа.
    Ответ написан
    Комментировать
  • Какие бывают библиотеки для лицензирования, и бывают ли?

    @Mercury13
    Программист на «си с крестами» и не только
    Я бы посоветовал посмотреть открытые части VmProtect (там и на PHP версия есть, и на C++). Они связаны именно с лицензированием.
    А также поискать где-то структуру VmProtect’овского hardware ID.
    Закрытые части, связанные с защитой лицензий от взлома и собственно виртуальной машиной, которая и дала название защите VmProtect, вы вряд ли найдёте. Да и вообще защита от копирования не может быть опенсорсной.
    Ответ написан
    Комментировать
  • Как с помощью какой функции можно int PID преобразовать в Handle?

    @Mercury13
    Программист на «си с крестами» и не только
    CreateProcess, последний параметр: processInfo.hProcess.
    https://stackoverflow.com/questions/42531/how-do-i...
    Ответ написан
    3 комментария
  • Как вывести результат программы на cpp в ms excel?

    @Mercury13
    Программист на «си с крестами» и не только
    Есть три варианта.
    1. Найти библиотеку работы с Excel. Самая маленькая и открытая — libxlsxwriter.
    2. Сохранять в более простых форматах. Самый простой из них — CSV. Не забудьте, что русский и английский Excel работают с разными CSV.
    3. Использовать OLE-автоматизацию Excel.
    У Спольского есть статья, почему форматы M$ Office такие сложные: https://rutlib5.com/book/25666/p/27
    Ответ написан
    Комментировать
  • Что означают надписи Ty, Alloc, Allocator в ошибке?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы попытались запустить функцию vector<A*>::erase с необычными параметрами. Какие — в ошибке не говорится, вот все перегрузки.
    https://ru.cppreference.com/w/cpp/container/vector...
    То есть функция принимает один или два итератора.

    Например, если вы хотите удалить значение, но неизвестно, где, нельзя его просто erase. А надо…
    // Спрессовать без перевыделения памяти, получить новый конец
    std::vector<A*>::iterator newEnd = std::remove(v.begin(), v.end(), whatToDelete);
    // Удалить освободившийся хвост скопом!
    v.erase(newEnd, v.end());


    Если вы хотите удалить по индексу…
    v.erase(v.begin() + indexToDelete);
    Ответ написан
  • Как правильно хэшировать файл большого размера?

    @Mercury13
    Программист на «си с крестами» и не только
    Я не понял, что значит «хэшировать». Если получить хэш-сумму — то все алгоритмы расчёта хэш-сумм позволяют скармливать файл небольшими блоками. И методика зависит библиотеки файлов и хэш-сумм, которой вы сейчас пользуетесь.
    Ответ написан
    Комментировать
  • Какая разница между передачей по указателю и по ссылке?

    @Mercury13
    Программист на «си с крестами» и не только
    О передаче объекта в функцию — обычно ссылка, НО!

    1. Если библиотека живёт на указателях (Qt) — указатель.
    void fillCombo(QComboBox* x) {}  // хорошо
    fillCombo(ui->comboHistory);
    
    void fillCombo(QComboBox& x) {}  // плохо
    fillCombo(*ui->comboHistory);


    2. Если возможен NULL — указатель. НО: существует паттерн «Null object», и он иногда бывает хорош.
    // Хуже, но возможно
    void import(AsyncRunner* asy) {
       if (asy) {
          asy->run([](){
            doImport(x);
          });
       } else {
          doImport(x);
       }
    }
    import(nullptr);
    
    // Лучше
    void import(AsyncRunner& asy) {
      asy.run([](){
        doImport(x);
      });
    }
    import(NoAsync::INST);


    3. Если передаём буфер данных — указатель.
    void write(size_t size, const char* data) {}

    4. Если объект невелик — значение.
    void save(std::string_view fileName) {}

    Объект может быть велик, но для него существуют специальные регистры — тогда…
    void transform(Matrix4 x) {}
    Есть одна машина с такими регистрами, не помню только, какая. Xbox?

    5. Идиома «by value + move», позволяющая избавиться от двух версий функции — Obj(string&) и Obj(string &&). Используется для объектов с простым перемещением и сложным копированием — обычно строк и структур STL.
    Obj::Obj(std::string aName) : name(std::move(aName)) {}
    Ответ написан
    Комментировать
  • Почему не любят c++ builder?

    @Mercury13
    Программист на «си с крестами» и не только
    Я работал, и профессионально тоже.
    1. Вторичен по отношению к Delphi, и те, кому нужна «амбаркадебра», осваивают Delphi. Носит на себе и Паскаль, и Си, и потому громадные EXE’шники.
    2. До недавнего времени — устаревший компилятор. Сейчас и под x86, и под x64 clang. Где-то до 2012 вообще x64 не было!
    3. Поставили не на тот кроссплатформенный фреймворк — не нравится мне FireMonkey.
    4. WinForms как-то проще в разработке.
    5. Долгое время — невнятная лицензионная политика «амбаркадебры».
    6. Долгое время — отсталость Delphi/VCL (например, нет Юникода).
    Ответ написан
    Комментировать
  • Как при изменение размеров окна удержать выведенный текст?

    @Mercury13
    Программист на «си с крестами» и не только
    Первое, самое главное. WM_PAINT рисует содержимое окна целиком. Если нужны тысяча надписей — или рисуйте их тысячу штук, или отпечатайте на внеэкранный BITMAP, или ещё что-нибудь.

    Это экономит память: Win3 хреново, но работала на одном мегабайте, лично видел. Но имеет побочный эффект — если прога перестаёт отвечать, например, в 95 с её вытесняющей многозадачностью, WM_PAINT никак не вызовешь, и будет белое окошко. XP (вроде она) кэширует содержимое окна и выводит его, пока прога не отвечает.

    Второе. InvalidateRect в WM_PAINT не имеет смысла. Смысл этого вызова — попросить Windows перерисовать окно, когда получится.
    Ответ написан
    2 комментария