• Чужой шрифт в рекламном видео. Добросовестка или нет?

    @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
    }
    Ответ написан
    Комментировать
  • Как сравнить два списка с помощью хеш-кода?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Реализация из Java8:
    public int hashCode() {
        int hashCode = 1;
        for (E e : this)
            hashCode = 31*hashCode + (e==null ? 0 : e.hashCode());
        return hashCode;
    }

    Из неё видно, что не совпало — у одинаковых списков хэши одинаковые. Но вспомни комбинаторику: если хэши одинаковы, объекты, СКОРЕЕ ВСЕГО, одинаковые, и один хрен нужно глубокое сравнение. Если разные — точно разные.

    2. Если просто сравнить два списка — сравнивай обычным equals, ничего ты не выиграешь от хэшей. Один хрен для вычисления хэша придётся пройти по всем данным. Хэши используй, если нужно сравнить, например, 100 объектов попарно — я так сжимал WAD’ы для Doom без потерь и рассинхронизаций демо-роликов. Сначала находил множества потенциально равных блоков, потом вёл глубокое сравнение.
    Ответ написан
    5 комментариев
  • Что лучше window.write(object) или object.write(window)?

    @Mercury13
    Программист на «си с крестами» и не только
    Да, относится — к MVC.
    В большинстве случаев лучше window.write(object).
    Внутренние структуры данных не должны зависеть от интерфейса, а интерфейс — может зависеть от внутренних структур данных.
    Если интерфейс сложный, могут быть какие-то промежуточные околоинтерфейсные объекты — например, чтобы изолировать или повторно использовать какую-нибудь логику. И вот в этих-то околоинтерфейсных структурах, каком-нибудь ComboBuilder, может быть writeTo(comboBox).

    Кроме того, в вебе, которому привычно видеть картину в момент T, а не в динамике, MVC если и есть, то сильно модифицированный.
    Ответ написан
    3 комментария
  • AUX и Jack 3,5 - это одно и то же?

    @Mercury13
    Программист на «си с крестами» и не только
    AUX ≠ Jack 3,5 ≠ наушники.
    1. AUX (неусиленный линейный выход) может быть и другими разъёмами — чаще всего DIN-5 или два RCA. Допустим, в моём самодельном переключателе колонки-наушники на колонки идут два RCA из-за сверхнадёжности, а на наушники — ну, так и быть, джек.
    2. На миниджеке 3,5 мм может быть и микрофон. У микрофонов отдельный механизм работы, и ухи от микрофона отличают омметром — наушник имеет сопротивление около 30 Ом, а микрофон — около 1к. И даже ухи с микрофоном, если джек 4-контактный.
    3. В советской аппаратуре существуют разъёмы для высокоомных наушников, и низкоомные могут плохо работать. (Сомневаюсь, что погорят — для проверки полярности часто берут и подключают к ним батарейку, хотя на AUX меньше вольта.) Впрочем, не видел ни одного устройства, где этот разъём — джек.

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

    @Mercury13
    Программист на «си с крестами» и не только
    Это стандартный студенческий код. Можно маленькую ревизию?
    1. Класс хранит строки в виде char*, ссылаясь на чужую память, и ничего хорошего не сделано с этой памятью. Подобные ссылки на чужую память хороши как оптимизация, когда практически всегда передаём строковые литералы (например, названия тэгов XML). А так стандартный способ хранить строку — std::string. Ну или char[], если не учили этого.
    2. Продолжение 1. С одной стороны, setMarka (например) имеет дело с внешней памятью, которой объект не владеет и которую не надо освобождать. С другой — Input передаёт во владение объекту буфер памяти, который освобождать НАДО.
    3. С возвратом true/false — он хорошо сказал. Сам класс должен решать, корректны ли данные.
    4. Деструктор — если std::string разрешён, лучше возьми его вместо const char* и забей на деструктор. Если запрещён — либо используй char[], деструктор не нужен. Либо сделай свой string, способный только управлять памятью неизменяемой строки, и деструктор нужен только ему. В промышленном программировании деструкторы редки: либо это реально какая-то необычная структура данных, либо просто компилятор заглючил и нужно хоть пустое, но тело в CPP-файле. Либо идиома pimpl (pointer to implementation, указатель на реализацию), призванная снизить количество каскадных include’ов — а значит, укоротить неполную сборку.
    5. char* car_name = "Toyota"; — работает только на очень старых компиляторах. Во всех известных мне строковый литерал имеет тип const char*.
    6. Input() должен быть чем-то внешним по отношению к машине: объект «машина» предназначен для хранения данных, и нечего притягивать к нему консоль, которой в программе может и не быть (например, она GUI).
    Ответ написан
  • На каком ЯП стоит писать программу для управления компьютерным клубом (десктоп)?

    @Mercury13
    Программист на «си с крестами» и не только
    Главное — сделать клиент, который сложно будет хакнуть и/или выбить. И тут что угодно, компилирующее в машинный код или что-то близкое: Delphi, C++, .NET. И придётся поспрашивать у опытных, как правильно защитить.

    Рабочее место админа — что угодно, хоть сайт в браузере.

    Сервер — машина, которая суткам работает в уголке и к которой даже админ не имеет доступа. Что угодно, хоть PHP.
    Ответ написан
    5 комментариев