Задать вопрос
  • Линейный аддресc? Умножение на 16, как это работает вообще и за чем в модели памяти, 32 бит, с 32 бит регистрами?

    @Mercury13
    Программист на «си с крестами» и не только
    У нас маленькие регистры и много памяти. То есть полный адрес задаётся регистровой парой, а не одним регистром. Можно сделать линейную адресацию, а можно сегментную. Объясню логику за сегментами.
    1. У нас линейная адресация, и надо по какой-то причине прибавить единицу к адресу. Если нижний адрес переполнится, надо переносить эту единицу в верхний — то есть делать длинный сумматор, увеличивать регистровый файл, постоянно работать с парами регистров и эту пару никак нельзя заменить одним — машина по сути превращается в костыльную 32-битную.
    2. Линейная адресация сильно усложняет загрузчики — им приходится обрабатывать так называемые relocations. Задан базовый адрес, и если загрузка случилась по другому. к определённым точкам в памяти надо прибавить разницу. В сегментной адресации этих relocations куда меньше: они задаются по сегментам, а не по точкам. (А в x64 для избавления от relocations ОЧЕНЬ МНОГО команд используют адресацию «от IP».)
    3. Совместимость с Intel 8080. Он тогда широко применялся, и IBM пошла на хитрость: после небольшой переделки проги под 8080 работали и на их ПК. Сейчас COM — странная технология Windows, а раньше COM — это было расширение маленьких исполняемых файлов в один сегмент длиной.
    Ответ написан
  • Почему строка конвертируется в неправильное число?

    @Mercury13
    Программист на «си с крестами» и не только
    Ваш текст представляет собой число, превосходящее диапазон int. В таком случае ваша реализация atoi выводит максимум возможного.
    Можно использовать:
    • sscanf long long
    • atoll (C++11)
    • stoll (C++11)
    • from_chars (C++17)
    Ответ написан
    1 комментарий
  • Зачем нужны интерфейсы при реализации внедрения зависимостей?

    @Mercury13
    Программист на «си с крестами» и не только
    Если предположить, что у интерфейса А всего одна реализация…
    1. Если объект А сам ссылается на объект Б — чтобы эти объекты не были единым комком, которые можно втянуть в проект только вместе.
    2. Чтобы ускорить перекомпиляцию при изменениях в объекте А.

    Но у интерфейса может быть и много реализаций, тогда…
    3. Чтобы сделать специальную версию А для модульных тестов объекта Б.
    4. Чтобы проще было расширять код или переносить модуль из проекта в проект: например, один и тот же упаковщик, принимающий на вход абстрактный поток, может работать хоть с файлами, хоть с сетью.
    Ответ написан
    Комментировать
  • Как сделать, чтобы конструктор при определённых условиях не компилировался — а не сваливал на runtime?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Вот действующий код.
    Хоть он на 20, простейшими define’ами (consteval → constexpr, constinit → пустота) можно собрать его и на 17.
    #include <iostream>
    #include <array>
    #include <string>
    
    enum class FromRawMem { INST };
    enum class NoValue { INST };
    
    #define consteval constexpr
    
    
    class Char4
    {
    public:
        using CppArray = std::array<char, 4>;
        constexpr explicit Char4(NoValue) : fBuf { { 0, 0, 0, 0 } } {}
        consteval Char4(const char (&x)[5]) : fBuf { { x[0], x[1], x[2], x[3] } } {}
        constexpr Char4(const Char4&) = default;
        Char4(FromRawMem, const char* data) { fBuf.asInt = *reinterpret_cast<const uint32_t*>(data); }
        constexpr const CppArray& toAr() const { return fBuf.asAr; }
        CppArray& toAr () { return fBuf.asAr; }
        constexpr std::string_view toSv() const { return { fBuf.asAr.data(), 4 }; }
    
        /// @return  byte-order dependent integer value
        /// @warning
        ///    DO NOT save toRawInt() as Intel, Motorola or any numeral system (decimal etc).
        ///    You MAY save it as raw memory, or use it for optimization.
        constexpr uint32_t toRawInt() const { return fBuf.asInt; }
        constexpr const char* data() const { return fBuf.asAr.data(); }
    private:
        union {
            std::array<char, 4> asAr;
            uint32_t asInt;
        } fBuf;
    };
    
    constexpr inline bool operator == (Char4 x, Char4 y) { return x.toRawInt() == y.toRawInt(); }
    constexpr inline bool operator != (Char4 x, Char4 y) { return x.toRawInt() != y.toRawInt(); }
    constexpr inline bool operator == (Char4 x, std::string_view y)
            { return y.size() == 4 && x.toRawInt() == *reinterpret_cast<const uint32_t*>(y.data()); }
    constexpr inline bool operator != (Char4 x, std::string_view y)
            { return !operator == (x, y); }
    constexpr inline bool operator == (std::string_view x, Char4 y)
            { return operator == (y, x); }
    constexpr inline bool operator != (std::string_view x, Char4 y)
            { return !operator == (y, x); }
    
    
    /// Size of enum class, no generic implementation.
    template <class Ec>
    constexpr size_t enumSize();
    
    namespace detail {
        /// Jut does not compile if arguments contain assignments
        constexpr int enumDummy(...) { return 0; }
    
        template <typename T, std::size_t...Is>
        consteval std::array<T, sizeof...(Is)>
        make_array(const T& value, std::index_sequence<Is...>)
        {
            return {{(static_cast<void>(Is), value)...}};
        }
    
        template <std::size_t N, typename T>
        consteval std::array<T, N> make_array(const T& value)
        {
            return make_array(value, std::make_index_sequence<N>());
        }
    }
    
    #define DEFINE_ENUM_SIZE(Name) \
        template <> constexpr size_t enumSize<Name>() { return static_cast<int>(Name::NN); }
    
    #define DEFINE_ENUM_N(Name, ...)  \
        enum class Name { __VA_ARGS__ };   \
        template <> constexpr size_t enumSize<Name>() { \
            enum Internal { __VA_ARGS__ , NNNNNN };  \
            detail::enumDummy(__VA_ARGS__);  \
            return NNNNNN; }
    
    
    enum class DummyElem { INST };
    enum class IncompleteArray { INST };
    enum class FillArray { INST };
    enum class PairwiseTempInit {INST };
    
    
    namespace detail {
        namespace array {
    
            template <auto K, class V>
            class KeyValue {
            public:
                static constexpr auto index = K;
                V && v;
                consteval KeyValue(V && aV) : v(aV) {}
            };
    
            // checkOneForRepeat
            template <class Ec>
            consteval void checkOneForRepeat() {}
    
            template <class Ec, Ec Only>
            consteval void checkOneForRepeat() {}
    
            template <class Ec, Ec First, Ec Second, Ec ... Rest>
            consteval void checkOneForRepeat()
            {
                static_assert(First != Second, "Repeating array keys!");
                checkOneForRepeat<Ec, First, Rest...>();
            }
    
            // checkForRepeat
            template <class Ec>
            consteval void checkForRepeat() {}
    
            template <class Ec, Ec Only>
            consteval void checkForRepeat() {}
    
            template <class Ec, Ec First, Ec Second, Ec ... Rest>
            consteval void checkForRepeat()
            {
                checkOneForRepeat<Ec, First, Second, Rest...>();
                checkForRepeat<Ec, Second, Rest...>();
            }
    
            template <class Ec, Ec ... args>
            consteval void checkKeys()
            {
                checkForRepeat<Ec, args...>();
            }
    
        }
    }
    
    template<auto K, class V>
    consteval auto kv(V && v) { return detail::array::KeyValue<K, V>(v); }
    
    
    template <class T, class Ec>
    class EcArray
    {
    public:
        static constexpr auto Size = enumSize<Ec>();
        using CppArray = std::array<T, Size>;
        using Elem = T;
        using iterator = Elem*;
        using const_iterator = const Elem*;
        constexpr CppArray& toAr() { return fBuf; }
        constexpr const CppArray& toAr() const { return fBuf; }
        constexpr Elem* data() { return fBuf.data(); }
        constexpr const Elem* data() const { return fBuf.data(); }
        constexpr size_t size() const { return Size; }
        constexpr iterator begin() { return fBuf.begin(); }
        constexpr iterator end() { return fBuf.end(); }
        constexpr const_iterator begin() const { return fBuf.begin(); }
        constexpr const_iterator end() const { return fBuf.end(); }
        constexpr const_iterator cbegin() const { return fBuf.begin(); }
        constexpr const_iterator cend() const { return fBuf.end(); }
    
        constexpr EcArray() = delete;
        constexpr EcArray(NoValue) {}
        constexpr EcArray(const EcArray&) = default;
        constexpr EcArray(EcArray&&) = default;
    
        EcArray& operator = (const EcArray&) = default;
        EcArray& operator = (EcArray&&) = default;
    
        template <class U>
        constexpr EcArray(NoValue, const U&& x) : fBuf {x } {}
    
        template <class ... Args>
        consteval EcArray(Args&& ... x)
            : fBuf { x... }
            { static_assert(sizeof...(Args) == Size, "EcArray size mismatch"); }
    
        template <class U, Ec K, class V, class ... Args>
        consteval EcArray(
                PairwiseTempInit, U&& temp,
                detail::array::KeyValue<K, V> first,
                Args&& ... rest)
            : fBuf { detail::make_array<Size, T>(temp) }
        {
            static_assert(sizeof...(Args) + 1 == Size, "EcArray pairwise size mismatch");
            detail::array::checkKeys< Ec, K, (std::remove_reference_t<decltype(rest)>::index)... >();
            initPairwise(first, rest...);
        }
    
    private:
        CppArray fBuf;
    
        consteval void initPairwise() {}
    
        template <Ec K, class V, class ... Args>
        consteval void initPairwise(
                detail::array::KeyValue<K, V> first,
                Args&& ... rest)
        {
            fBuf[static_cast<size_t>(K)] = T { first.v };
            initPairwise(rest...);
        }
    };
    
    
    DEFINE_ENUM_N( Letter, A, B, C )
    
    extern const EcArray <Char4, Letter> names2;
    
    //const EcArray <Char4, Letter> names { "alph", "brav", "char" };
    
    constinit const EcArray <Char4, Letter> names2
        { PairwiseTempInit::INST, Char4 { NoValue::INST},
          kv <Letter::A> ( "alp1" ),
          kv <Letter::B> ( "bra1" ),
          kv <Letter::C> ( "cha1" ) };
    
    
    int main()
    {
        std::cout << "Hello World!" << std::endl;
        return 0;
    }
    Ответ написан
    Комментировать
  • Почему цикл do-while работает странно?

    @Mercury13
    Программист на «си с крестами» и не только
    1. in.read() читает один байт.
    2. Введённые вами f и ВВОД остаются в буфере.
    3. Данные передаются в поток, когда вы нажтмаете ВВОД.
    Потому первый раз читает f, второй раз — забуферизированный ВВОД.
    Используйте java.util.Scanner, который позволит считывать строчку целиком.
    Или, на худой конец, пропустите забуферизированные байты System.in.skip(System.in.available());
    Ответ написан
    4 комментария
  • Как создать проект с++ на основе готового кода?

    @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
    Программист на «си с крестами» и не только
    Итак, на стеке лежит локальный объект, и так совпало, что его адрес совпадает с регистром esp. Стек на x86 растёт вниз, так что такое бывает.
    Для этого объекта мы вызываем функцию с соглашением вызова cdecl thiscall и одним dword-параметром, предположительно указателем. Функция возвращает указатель/ссылку на объект — видимо для «текучего интерфейса».

    Как я понял, вы подставным DLL или подобной дрянью хотите вызвать эту функцию, верно? Тогда в DLL пишем примерно такое.
    #include <iostream>
    
    class X
    {
    public:
        // Наделай полей — непонятно, какой нужен размер объекта, но минимум 7 dword
        uint32_t field0 = 0, field4 = 0, field8 = 0, fieldC = 0,
               field10 = 0, field14 = 0, field18 = 0;
        // Просто тестовая функция, тебе не нужна
        X& doSmth(void* param);
    };
    
    
    // Просто тестовая функция, тебе не нужна
    X& X::doSmth(void* param)
    {
        std::cout << "My address is " << this << std::endl;
        std::cout << "My param is " << param << std::endl;
        return *this;
    }
    
    // Известно, что параметр — указатель/ссылка, но какого типа — неизвестно.
    // Пусть будет void*.
    using PFunc = X& (X::*)(void*);
    
    int main()
    {    
        PFunc func = &X::doSmth;  // Тебе надо reinterpret_cast<PFunc>(0x471440)
        X x;
        auto param = reinterpret_cast<void*>(0x5678);  // Или придумай, чему должен равняться этот param
        (x.*func)(param);
        return 0;
    }
    Ответ написан
    Комментировать
  • Какой способ отрисовки использован в игре?

    @Mercury13
    Программист на «си с крестами» и не только
    Рейкастинг и есть, только не по пикселям, а по столбцам.
    Ответ написан
    5 комментариев
  • Как избавиться от явного задания типа в вариативном шаблоне (двухмерный массив, инициализируемый строчками)?

    @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;
    }
    Ответ написан
    Комментировать
  • Где и как используют деревья в программировании?

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

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

    @Mercury13
    Программист на «си с крестами» и не только
    ceil(log2(n + 1))

    Поскольку ответов на каждый конкретный вопрос возможны три штуки (больше/меньше/угадал), тупая оценка количеством битов невозможна, надо учитывать зависимости между этими ответами.

    Доказательство.
    Докажем обратное: за k шагов можно угадать 2k−1 чисел.

    БАЗА. 1 угадывается с первого раза. 2 с первого раза уже не угадаешь.

    ШАГ. k → k+1. Другими словами, нам известно, что 2k−1 угадать можно, а 2k уже нельзя.
    Берём центральное, и остаётся 2k−1 слева и 2k−1 справа. → n = 2·(2k−1)+1 = 2k+1−1
    Если n = 2k+1 или больше, хоть в одной половинке будет 2k, что, по предположению индукции, невозможно.
    Ответ написан
    4 комментария
  • Как вывести на автономный монитор или телевизор картинки, меняющиеся нажатием кнопки?

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

    @Mercury13
    Программист на «си с крестами» и не только
    Я сделал вот такой код (простите, для простоты «с крестами»).
    #include <stdio.h>
    #include <iostream>
    
    int main() {
        int a = getchar();
    
        while (a != '\n') {
            std::cout << a << "-" << static_cast<char>(a) << std::endl;
            a = getchar();
        }
    }
    
    143-П
    224-р
    168-и
    162-в
    165-е
    226-т

    Так что не здесь полом. Но учтите, что работа была под виндой, а значит, в кодовой странице DOS-866. Подкиньте ОС, рабочую кодировку и чуть больше кода обвязки.

    UPD1. Если символов 12 вместо 6 и ОС Android — перед нами кодировка UTF-8. И выводить в консоль по одному символу не очень кузяво, поскольку для русского текста получаются неполные кодовые позиции. Закройте буфер нулём и выведите целиком.
    Ответ написан
  • Влияет ли видеокарты на скорость загрузки вебсайтов?

    @Mercury13
    Программист на «си с крестами» и не только
    Если видяха «затычка» — может влиять, и тогда приходится в браузере отключать аппаратное ускорение.
    Если хоть немного тянет подобие игр — не влияет.
    Но влияет не на загрузку, а на работу веб-проги — медленно прокручивается, медленно идёт перетягивание блоков…
    Проверено. На рабочей машине nVidia Quadro NVS 295 — самое дешёвое, что вообще существовало на рынке, и к тому же пассивное. То есть именно затычка. Процессор топовый AMD, без встроенного видео.

    UPD1. Некоторые кодеки с аппаратным ускорением могут напрочь отказать — так, в Slack с аппаратным ускорением при трансляции экрана видим картину Малевича.

    То есть факт: Intel Core i5 + встроенное видео >> AMD Ryzen 7 + nVidia Quadro NVS 295.
    В вебе на аппаратном ускорении.
    Ответ написан
    1 комментарий
  • Отказала библиотека ODBC/Win32, какой пакет MSYS откатить?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Неверный, но очень интересный механизм спрячу под спойлер.
    Повторяю, это неверно!
    1. *.dll → *.def

    c:\msys64\mingw32\bin\gendef.exe odbc32.dll

    2. *.def → *.a

    c:\msys64\mingw32\bin\dlltool.exe --dllname odbc32.dll --input-def odbc32.def --output-lib libodbc32_merc.a

    win32-g++: {
        contains(QMAKE_HOST.arch, x86_64):{
            # x64
            LIBS += -lodbc32
        } else {
            LIBS += -lodbc32_merc
        }
    }


    А что надо — вытащить из MinGW ODBC для Windows (c:\msys64\mingw32\i686-w64-mingw32\include\) и подкорректировать #include, чтобы брало из текущего каталога, а не из стандартного.
    // SqlUnglitch.h
    #ifdef _WIN32
      #include "SqlWin/sql.h"
      #include "SqlWin/sqlext.h"
    #else
      #include <sql.h>
      #include <sqlext.h>
    #endif

    Причина: в MSYS появилась своя библиотека ODBC с блэкджеком и шлюхами. Под Win64 по соглашениям вызова совпало, а под Win32 — нет. Почему-то при -O0 как-то работает, а уже при -O1 — уже нет.
    Ответ написан
    Комментировать
  • Почему прошивки пишут на С?

    @Mercury13
    Программист на «си с крестами» и не только
    Потому что низкоуровневый софт должен…
    • Быстро выполняться. Потому что его выполняют или в глубоких циклах (например, ОС), или на слабом железе.
    • Расходовать мало памяти и не «течь». Потому что его часто выполняют на слабом железе. Или в чужих стеках, как драйвер.
    • Содержать мало зависимостей. Если мы зависим от большой библиотеки вроде Qt, а её реализации на данной машине нет — выкуси. Точно так же интерпретатор Питона может оказаться лишней зависимостью. И многопоточка, которая часто требуется для «мусорщика».
    • Быть совместимым с кодом на других языках. Это касается системного и драйверного кода, который вызывают из прикладного ПО (или, наоборот, прикладной кода из системной проги) — и даже с кодом на разных версиях .NET в расширениях оболочки Windows есть вопрос.
    • И в то же время требуется некая доля переносимости и абстракции. Например, мы пишем джойстик на AtMega и не хотим мучиться с длинными числами — ЯВУ лучше будет, чем ассемблер. 10 бит АЦП на 8-битном процессоре уже длинное число!!

    Почему Си? У него есть две фишки: большое поле для ручной оптимизации (ключевое слово register, op++), и он полагается на две ассемблерных утилиты — линкер и библиотекарь (tlink и tlib, например). Из-за этого компилятор Си довольно просто написать под новую машину, и на НЕоптимизирующем компиляторе можно писать довольно быстрый код.
    Ответ написан
    Комментировать
  • Что лучше 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
    Программист на «си с крестами» и не только
    Не сгорит. Либо будет работать на своей частоте (чаще всего, если разрыв по поколению невелик), либо полный отказ без всяких перегревов (если ставите что-то совсем уж старое/новое).
    Ответ написан
    Комментировать
  • Какой “App type” выбрать в генераторе политики конфиденциальности для бесплатной игры с внутренними покупками и рекламой?

    @Mercury13
    Программист на «си с крестами» и не только
    Ad supported — поддерживаемая рекламой.
    Разница между Freemium, Ad Supported и Commercial только в преамбуле. Один хрен вам придётся подкорректировать политику конфиденциальности под свои цели — например, как реально используются куки.
    Ответ написан
    6 комментариев
  • Можно ли ускорить архивацию/разархивацию за счет распараллеливания ??

    @Mercury13
    Программист на «си с крестами» и не только
    Если использовать стандартную библиотеку сжатия (например, ZLIB), будет проблематично. Нужно как минимум писать своё сжатие с блэкджеком и многопоточностью.
    Однако можно распараллелить разархивацию и интерпретацию того, что разархивировалось, и это помогает. Проверено (писал сохранение в простой блочный формат, запаковываемый в ZIP).
    Архивация на ZLIB с высшей степенью сжатия упирается не в SSD, а в процессор. Тоже проверено. Для баланса между сжатием и остальной функциональностью установил степень сжатия в четвёрку.
    Ответ написан
    Комментировать