• Как решить ошибку "String is not null terminated"?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы неправильно пользуетесь функцией strcat_s.
    Традиционно в Си (видимо, из-за особенностей машины PDP-11) каждая строчка заканчивается нулевым символом.
    Смысл strcat_s — если строка находится в буфере ограниченной длины и по какой-то причине не нуль-терминированная, функция не полезет в «левую» память, а ограничится размером буфера. Вторым параметром должна быть длина буфера, а не strlen, который обесценивает весь смысл суффикса «safe».
    Ответ написан
    Комментировать
  • Как поделить на о в С++?

    @Mercury13
    Программист на «си с крестами» и не только
    Деление на целочисленный 0 невозможно, происходит авария «деление на 0».

    В процессорах, которые делят 2w:w → w, эта авария происходит и в других случаях. Скажем, если слово — это две десятичных цифры, то 1000:2 даст ошибку: 500 не укладывается в эти две цифры. В Си++, который умеет делить только w/w, такое сделать можно только на ассемблере.

    Деление конечного на дробный 0.0 даёт ±∞ — особое «число», которое больше/меньше любого конечного.
    Деление 0.0/0.0 даёт NaN (not a number, не-число).

    Откуда вы взяли мантиссу 1,87235 — я не знаю. Минимальное денормализованное число в float 1.4e−45, в double 4.9e−324. Почему так мало знаков — да потому что погрешность у таких чисел ±100%: меньше только 0, а следующее вдвое больше.

    UPD. В редко используемом и очень медленном extended (= long double) есть что-то похожее — 1.9e−4951.
    Ответ написан
    Комментировать
  • Как правильно оценить сложность алгоритма O(n)?

    @Mercury13
    Программист на «си с крестами» и не только
    f(x) = O(g(x)) при x→y — это так называемый символ Ландау.
    И означает, что при x, достаточно близких к y, f(x)<k·g(x). Так что 2x или 1000x — извините, не важно.

    Отсюда же запись O(log n) — ведь разные логарифмы отличаются на константу, которую символы Ландау съедают.

    Чем символы Ландау интересны программистам?
    1. Кэшами, быстрым процессором, «хитрым» программированием и прочим на больших наборах данных можно выиграть, например, в разы. Порядком сложности алгоритма — намного, намного больше.
    2. Пока закон Мура действовал, объёмы данных росли экспоненциально — так что быстро доходило до того, что программу начинали использовать на наборах данных, для которых она просто не предназначалась.
    3. Практически приемлемые алгоритмы обычно имеют небольшую сложность — например, до O(n³). И, например, линейный алгоритм за приемлемое время обработает миллионы элементов, n log n — сотни тысяч, n² — тысячи, n³ — сотни.
    4. Программисты отлаживают на небольших наборах данных, которые можно обработать вручную. Так что разница между отладочными и боевыми данными бывает большая — а значит, порядок сложности должен влиять сильнее, чем остальные факторы.
    Ответ написан
    1 комментарий
  • Как уменьшить выходной exe при компиляции?

    @Mercury13
    Программист на «си с крестами» и не только
    Это вообще как компилируете?
    Если у вас MinGW и консольная программа, советую что-то вроде
    -O3 -Os -static-libgcc -static-libstdc++ -static -lpthread

    Получается самодостаточный EXE’шник, и для небольших программ ≈400K, для программ побольше — около 2М.
    Ответ написан
    Комментировать
  • Что за функция swow?

    @Mercury13
    Программист на «си с крестами» и не только
    Это чья-то собственная. Вы её и не найдёте. Особенно вместе с общими названиями generate и foo.
    Шерстите свой исходник. А если он не полный — вы сами себе злобный буратино.
    Ответ написан
    Комментировать
  • Почему финализированные классы в исходниках java имеют private конструкторы?

    @Mercury13
    Программист на «си с крестами» и не только
    Ничем особенным. Просто библиотечные функции сильнее защищают от «нештатного» использования.
    Ответ написан
    Комментировать
  • Как выполнить размещение k элементов из n?

    @Mercury13
    Программист на «си с крестами» и не только
    Будут повторы?
    Если не будет — то достаточно отсортировать char’ы и использовать числовой алгоритм.
    Если будут — ищите «размещения с повторами», и тоже сортируйте.
    Ответ написан
    Комментировать
  • Что обозначают записи: Class object(&anotherObject); и AnotherClass anotherObject(10);?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Создать в стандартном месте (на стеке или в сегменте данных) объект object типа Class с вызовом конструктора Class::Class(AnotherObject*).
    2. Создать там же объект anotherObject типа AnotherClass с вызовом конструктора AnotherClass::AnotherClass(int).
    Ответ написан
    Комментировать
  • Почему при выводе элемента из перечисления выводит не нужное мне значение?

    @Mercury13
    Программист на «си с крестами» и не только
    Полагаю, дело в системе сборки — нечто подобное я испытывал и в Doom (старом, 1994 года), где makefile редактировался руками.

    Например, у вас было
    typedef enum Buttons{
        SAVE,
        OPEN,
        SORT,
        EXIT
    }Buttons;

    После того, как вы откорректировали enum, один файл перекомпилировался, другой нет — отсюда такой артефакт.
    Ответ написан
  • Почему не проходит запрос из-за foreign key?

    @Mercury13
    Программист на «си с крестами» и не только
    Подозреваю глюки с кодировками. В проге-админке работает?
    Ответ написан
    Комментировать
  • Почему один и тот же код на python и c++ дает разный результат?

    @Mercury13
    Программист на «си с крестами» и не только
    hypot в Си даёт гипотенузу, а a²+b² в змее-питоне — квадрат гипотенузы.
    Ответ написан
    Комментировать
  • Как заполнить map английскими буквами и вывести его?

    @Mercury13
    Программист на «си с крестами» и не только
    Потому что map — это функциональное соответствие. Одному ключу соответствует одно значение.
    Или используйте multimap. Или варьируйте ключ, а не делайте жёсткой единицей.
    Ответ написан
    Комментировать
  • Линейный аддрес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 комментариев