Задать вопрос
  • Как сделать чтобы программа не запускала процес на каждый аргумент, а запускала один процес на все аргументы?

    @Mercury13
    Программист на «си с крестами» и не только
    Под Windows это делается через DDE.
    Штука сильно устаревшая, однако осталась именно на это — поддержку нескольких файлов через файловый менеджер.
    Ответ написан
    2 комментария
  • Как заменить мышь, и установить чувствительность как было раньше?

    @Mercury13
    Программист на «си с крестами» и не только
    X — это DPI мыши. Я сам чувствителен к этому самому DPI, но я не настолько крутой геймер и мне ±15% вполне покатит.

    Купи геймерскую мышь с плавной установкой DPI и установи такой же, какой был.

    Кроме того, есть ещё один скрытый параметр — качество сенсора. В 2006 было время: покупаешь мышку, а она время от времени устраивает срыв: курсор уходит ХЗ куда. Разумеется, это недопустимо, но умные люди подключили методы решения некорректно поставленных задач, и мыши перестали срываться. Главная фишка этого метода: чем меньше решение по модулю, тем оно предпочтительнее. Это приводит к т.н. отрицательному ускорению мыши: если мышь походит А→Б быстро, курсор пройдёт меньшее расстояние, чем если бы её провели медленно. Если старая (или новая) мышь не очень качественная, отклик будет немножко не такой.
    Ответ написан
    Комментировать
  • Работа с рисованием в Qt. Почему не получается рисовать после оператора if?

    @Mercury13
    Программист на «си с крестами» и не только
    Дело тут вот в чём. События рисования могут проскакивать когда угодно по любому чиху, и потому механизмы перерисовки надо делать такие, что когда угодно этот paintEvent() проскочит — изображение в окне будет корректно восстановлено.

    Например:
    enum class Shape { NONE, LINE, ELLIPSE, RECTANGLE };
    
    ... в форме...
    Shape shareToDraw = Shape::NONE;

    …соответственно в коде нажатия кнопок устанавливаем эту shapeToDraw,
    а paintEvent реагирует на неё.

    У вас же, как только paintEvent() повторно проскочит, ни одно событие не будет отмечено, и он ничего не сделает. А ведь он может дважды проскочить, чтобы нарисовать непрямоугольную область. Или если оконный менеджер что-то попросил.
    Ответ написан
  • Почему поведение fscanf ( stdin, "%c", &c ) различается при чтении EOF в msvc и gcc?

    @Mercury13
    Программист на «си с крестами» и не только
    В таком случае, когда есть подозрение на конец файла, надо проверять возвращаемое значение функции fscanf:
    • EOF — файл закончился;
    • 0 — не прочитали (в данном случае, когда читаем символ такого явно не будет);
    • 1 — прочитали.

    Если во втором случае MSVC возвращает EOF, но заполняет — поведение некузявое, но допустимое.
    Если во втором случае MSVC возвращает 1 — поведение дрянь.

    Вообще для такого дела fscanf — большая пушка, лучше использовать fgetc.
    Ответ написан
  • Чем отличаются любительские МК от промышленных?

    @Mercury13
    Программист на «си с крестами» и не только
    AVR, сердце Arduino, когда-то имел «любительские» и «промышленные» версии. Я уже не помню буквенные индексы.
    Промышленные отличались более высоким диапазоном рабочих температур.
    Сейчас их нет — выход хороших микросхем, видимо, уже достаточно большой. Нет нужды особо продавать «не-совсем-хорошие» микросхемы.
    Ответ написан
    7 комментариев
  • Чужой шрифт в рекламном видео. Добросовестка или нет?

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

    @Mercury13
    Программист на «си с крестами» и не только
    Creative Commons — это лишь стандартные лицензии.

    Использование фото в ролике НЕ будет добросовестным использованием, надо брать фото на стандартных неэксклюзивных условиях или выпрашивать у автора персональную лицензию. Так, в своей программе «Юникодия» я специально просил разрешение на использование двух шрифтов — сирийского и кави. Сирийский не получил — значит, тот, кто будет её распространять коммерчески, должен получить сам. Кави получил — соответственно, пока он в составе «Юникодии», просто бери и не договаривайся.

    Поскольку Армения 80-х была ещё до Creative Commons, единственный способ получить её на условиях Creative Commons — кто-то сфоткал и много десятилетий спустя выложил. Все условия CC, кроме CC0 (аналога отдачи во всеобщее достояние), ТРЕБУЮТ указания автора. Но: можно поискать по государственным архивам, их работы зачастую всеобщее достояние. Не нашим, правда — с этим у нас туго — а американским и немецким.
    Ответ написан
  • Что по смыслу делает этот if?

    @Mercury13
    Программист на «си с крестами» и не только
    Мы тут считываем текстовый файл, и разбор файла по строкам происходит так.
    1. Считываем кусок файла.
    2. Находим \n, если он не в начале буфера.
    3. Движемся назад, пока не увидим начало буфера или другой \n. Отсюль досюль — это строка текстового файла.
    4. Если при компиляции включено FIND_LIB_NAME — пропусти четыре поля, отделённых пробелом, затем кучу пробелов (один или больше), и всё, что до \n — это имя библиотеки. Прямо в буфере заменяем символ конца строки текстового файла на символ конца Си-строки, обрабатываем и возвращаем как было.

    Вообще мне этот исходник не нравится — он сильно завязан на устройство конкретного MAP-файла.
    1. Работа с offset подозрительная — то ли длина каждой строчки является степенью двойки и всё оказывается в порядке, то ли не понимаю что.
    По идее, должны быть два дополнительных блока: 1) если мы упёрлись в конец и хоть один \n считали — всё, что осталось, мы переносим в начало буфера и продолжаем считывание дальше. 2) Если ни одного \n не считали — файл совсем уж странный, слишком длинная строка, выкидываем ошибку.
    2. Если попадёт файл, чей формат совсем другой, система, конечно, не вылезет за пределы буфера, но будет читать непонятно что непонятно откуда. Границами чтения должно быть «отсюль досюль», а не весь буфер. Попытался выяснить, откуда взялся файл — не удивительно, что последний его коммит — это тупая защита от чтения за пределами буфера.
    Ответ написан
    Комментировать
  • Можно ли перекрасить иконку без внутреннего API Qt?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Прямо из исходников applyQIconStyleHelper…
    if (mode != QIcon::Normal) {
        QStyleOption option(0);
        option.palette = QGuiApplication::palette();
        const QPixmap generated = QApplication::style()->generatedIconPixmap(mode, *workingPix, &option);
        if (!generated.isNull()) {
            *workingPix = generated;
        }
    }
    Ответ написан
    Комментировать
  • Возможно ли достичь аргумента с нескольким определением типа?

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

    А так здесь есть два вопроса.
    1. А что напишем в скобках вместо непонятного return?
    2. В какой код оно должно скомпилироваться?

    Пример стандартный шаблонный.
    template <class Device>
    SomeFunction getProcAddress(const Device& device, const std::string& name);
    
    template <>
    inline SomeFunction getProcAddress<VkInstance>(
            const VkInstance& device, const std::string& name)
      { return vkGetInstanceProcAddr(device, name.c_str()); }


    Это стандартное использование шаблонов Си++ с далёкого 1998 года.

    Пример через if constexpr. Си++17, значит.
    template <class Device>
    inline SomeFunction getProcAddress(const Device& device, const std::string& name)
    {
      if constexpr (std::is_same_v<Device, VkInstance>) {
        return vkGetInstanceProcAddr(device, name.c_str());
      } else {
        // false нельзя! — проверка произойдёт в любом случае, будет компилироваться ветка или нет.
        static_assert(std::always_false_v<Device>, "Unknown type");
      }
    }

    Используется в функции std::visit, чтобы исполнить разный код для разных вариантов std::variant и ничего не забыть.

    Что написано в скобках — ну, сами видите. Во что скомпилируется — в две разных функции.

    В некоторых случаях — вероятно, не в вашем — можно ещё поиграться с виртуальным полиморфизмом.
    Ответ написан
  • Кроссплатформенное программирование на C?

    @Mercury13
    Программист на «си с крестами» и не только
    Что тогда делают? Есть три варианта.
    1. Перейти на кроссплатформенную библиотеку (Qt, например).
    2. Наладить свою небольшую библиотеку, которая когда-нибудь станет кроссплатформенной.
    3. Наладить механизм псевдонимов.
    Эти варианты можно объединять: что-то перевести на другую библиотеку, что-то написать своё.

    Примеры из личного кода.

    ОДИН. Ну, например, собственные механизмы работы с путями к файлам потихоньку уходят в сторону std::filesystem::path.

    ДВА. Ну, допустим, сделал свою библиотеку доступа к файлам — бонуса три. 1) Есть функции вроде writeIW (Intel word). 2) Проще писать свои абстрактные потоки, чем с std. 3) Феноменальная скорость под Windows (использует нечастый, но быстрый overlapped API с двойной буферизацией). На остальных ОС — обычная обёртка над FILE*.

    ТРИ. std::random_device из MinGW 9 давал детерминированную последовательность. Потом попытался бросить эту обходную ветку, но кто-то из программистов пожаловался — на его машине r_d просто не инициализировался.
    #if defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__)
    
        #define MINGW_RANDOM_DEVICE_WORKAROUND
    
        class MingwRandomDevice {};  // куча WinApi, опустим
    #else //defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__)
        #include <random>
        using MingwRandomDevice = std::random_device;
    #endif //defined(__MINGW32__) && defined(__GNUC__) && !defined(__clang__)
    Ответ написан
    1 комментарий
  • Почему разрешен upcast в RTTI?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Принцип подстановки Лисков — один из важных принципов организации интерфейса объекта. Смысл: само устройство абстракции должно допускать такое, что у нас сын C, но мы безопасно могли работать с отцовскими типами A и B.
    Пример: Отец — прямоугольник с setWidth/setHeight. Сын — квадрат. Значит, уже при проектировании абстракции надо допустить, что setWidth/setHeight или изменит заодно и высоту, или откажется работать, или…
    2. Принцип достаточности. Зачем работать с типом C, если достаточно с B?

    UPD. А для чего этот dynamic_cast вообще? ООП без него проживёт, и часто dynamic_cast — это расписка в плохой конструкции объектов. Но в первую очередь он нужен на API настолько общие, что не совсем понятно, как сделать просто и эффективно. Или требование бинарной совместимости, что важно для всяких там VCL и Qt.
    Ответ написан
    Комментировать
  • Как в Qt сделать DecorationRole, зависящую от DPI экрана?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Опять приходится отвечать самому.

    1. Нашему QListBox’у задаём setIconSize в дипелях.
    2. В data(Qt::DecorationRole) использовать конструктор QIcon(QIconEngine*). Система переводит дипели в пиксели, и работает QIconEngine — объект, содержащий кучу кода и немножко данных, призванный синтезировать иконку нужного размера в аппаратных пикселях.

    Если нужны ещё и разные размеры иконы — патчить QStyledItemDelegate.initStyleOption. Вероятно, тоже в дипелях (не проверял).
    Ответ написан
    Комментировать
  • Выдаст ли ошибку при аллоцировании памяти?

    @Mercury13
    Программист на «си с крестами» и не только
    Нормально.
    Аварии в деструкторе и конструкторе — дела сложные, но возможные.
    Но тут ни того, ни другого не будет. До вызова конструктора просто не дойдёт.
    } catch (const std::bad_alloc&) {}
    Ответ написан
    Комментировать
  • Как сделать элемент поверх другого в QT?

    @Mercury13
    Программист на «си с крестами» и не только
    Самый обычный QWidget
    #wiRound {
      background-color: yellow;
      border-radius: 20;
    }

    6390801eab617817237396.png
    Сам QWidget брошен куда попало, кнопки же расставлены через стандартный vertical layout.
    Ответ написан
  • Как исправить ошибку в коде из-за сравнения с кириллицей/русским алфавитом?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак, нам нужна обработка русского текста, портабельно и поменьше геморроя. Если константа 'Д' многосимвольная — значит, кодировка исполнения UTF-8 и на string забивай, тяжело будет. Работаем в строчке пошире: wstring, u16string или u32string. Главное, разобраться, как правильно выводить всё это в консоль — например, через wcout. То есть:
    wchar_t a;
    if (a == L'Д') {}


    Иногда можно работать и в UTF-8: std::string s; if (s.starts_with("Д")) {} (Си++20!!) Но инструментарий поуже будет, а под Windows с разнобоем кодировок — не советую.
    Ответ написан
  • Будет ли работать бинарный поиск, если в массиве есть пробелы?

    @Mercury13
    Программист на «си с крестами» и не только
    Что такое вообще «пробелы»?
    1. Пробелы в исходном коде: за пределами закавыченных строк это только оформление и в исполнении не участвует. Ну и слова, разумеется, нужно разделять пробелами — как в паскалевском «packed array» или сишном «int main».
    2. Пропуски: не 1,2,3, а 1,4,5. Да, для этого бинарный поиск и предназначен: массив отсортирован, никаких других правил нет, найти или сам элемент, или место, куда вставить его.
    Например, ищем 7: 6 → больше, 13 → меньше, 12 → меньше. Не нашли; если нужно вставить — то после 6-ки.
    Ищем 1: 6 → меньше, 4 → меньше, 1 → попали.
    Ответ написан
    1 комментарий
  • Какя разница в формулах теоремы Байеса?

    @Mercury13
    Программист на «си с крестами» и не только
    В знаменателе — формула полной вероятности. Вот и всё.
    p(B) = p(B|A)·p(A) + p(B|¬A)·p(¬A)

    Для чего? Да просто p(B) в большинстве случаев хрен поймёшь, и его приходится вычислять непрямо. Например:
    A — письмо является спамом
    B — в письме есть слово «sex»
    Видим в письме слов «sex» — спам ли оно?
    Мы можем собрать базу спама со словом «sex», и базу обычной переписки с этим словом, и вычислить p(B|A) и p(B|¬A). А p(A) и p(¬A) вычисляются уже на компе конечного пользователя в зависимости от того, насколько жёстко его спамят.

    Пример второй. Каждый тысячный водитель — пьяный. Алкотестер чётко видит алкаша, но останавливает каждого сотого трезвого. Какой процент из приехавших в больницу действительно пьянствуют за рулём?
    U — проехавшие через пост водители
    A — пьяный
    B — алкотестер сработал
    Аналогично, p(B) заранее неизвестен, но приходится вычислять по полной вероятности. И вроде бы при таких цифрах один из одиннадцати попавшихся реально пьяный. И это затрудняет антитеррористические меры: если по городу-миллионнику ходит сотня террористов, какая должна быть точность, чтобы не ломать невинные жизни!
    UPD: чуть меньше 1/11: p(B|A)=1, p(A)=1/1000, p(B|¬A)=1/100, p(¬A)=999/1000,
    итого с сокращением на 1000 будет 1/(1+999/100)=100/1099.
    Ответ написан
    Комментировать
  • В каких случаях логичней чтобы получить половину умножать на 1/2, а в каких делить на 2?

    @Mercury13
    Программист на «си с крестами» и не только
    ЦЕЛЫЕ ЧИСЛА / ФИКСИРОВАННАЯ ЗАПЯТАЯ
    ·0,5 в фиксированной запятой нет никакого смысла. /2 и арифметический сдвиг >>1 ведут себя немного по-разному на отрицательных числах, и как сейчас оптимизируют /2 с сохранением точности до бита — я не в курсе (Godbolt показывает пекло какое-то на пять команд — и оно быстрее, чем div?).

    ДРОБНЫЕ ЧИСЛА
    С /2 и ·0,5 никакой разницы, но второе быстрее. Если коэффициент не умещается в компьютерное дробное (⅓, например) — если нет никакого сакрального смысла в точности до бита, можно множить.
    Ответ написан
    Комментировать
  • Как использовать std::begin и std::end в функциях для массивов?

    @Mercury13
    Программист на «си с крестами» и не только
    Я вообще не в курсе, как взаимодействуют Сишный int[] и Си++-ный &arr.
    Но получается, это под капотом превращается в банальный const int*, для которого нет std::begin/end.

    Я бы предложил ещё два распространённых механизма. Первый желательно делать лёгким инлайном, который под капотом превращается в data/size или std::span (если Си++20).

    template <size_t N>
    void myA(const int(&arra)[N], const int(&arrb)[N])
    {
      auto arra_begin = std::begin(arra);
    
      std::cout << *arra_begin << std::endl; // 1
    }
    
    // Си++20!!!!!!!!!!
    void myB(std::span<int> arra, std::span<int> arrb)
    {
      auto arra_begin = std::begin(arra);
    
      std::cout << *arra_begin << std::endl; // 1
    }
    Ответ написан
    Комментировать