Задать вопрос
  • Как сделать такой финт ушами с double?

    @Mercury13
    Программист на «си с крестами» и не только
    Почему нельзя? Пишу на Си с крестами, но там ничего специфичного нет, кроме парочки перестраховок.
    В Си++20 появился ещё и bit_cast.

    #include <iostream>
    
    union DoubleInt {
        double asDouble;
        uint64_t asInt;
    };
    
    static_assert(sizeof(double) == sizeof(uint64_t), "Strange machine with double != int64");
    
    constexpr int BITS_MANTISSA = 52;
    constexpr int BITS_EXPONENT = 11;
    constexpr int BITS_SIGN = 1;
    
    static_assert(BITS_MANTISSA + BITS_EXPONENT + BITS_SIGN == 64, "Programmer's funkup");
    
    constexpr uint64_t MANTISSA_UNIT = uint64_t(1) << BITS_MANTISSA;
    constexpr uint64_t MANTISSA_MASK = MANTISSA_UNIT - 1;
    
    constexpr int EXPONENT_SHIFT = BITS_MANTISSA;
    constexpr uint64_t EXPONENT_MAX = (uint64_t(1) << BITS_EXPONENT) - 1;
    constexpr uint64_t EXPONENT_ORIGIN = EXPONENT_MAX >> 1;
    constexpr uint64_t EXPONENT_MASK = EXPONENT_MAX << EXPONENT_SHIFT;
    constexpr uint64_t EXPONENT_SHIFTED_ORIGIN = EXPONENT_ORIGIN << EXPONENT_SHIFT;
    
    constexpr int SIGN_SHIFT = BITS_MANTISSA + BITS_EXPONENT;
    constexpr uint64_t SIGN_MASK = uint64_t(1) << SIGN_SHIFT;
    
    int main()
    {
        DoubleInt x { -3.45 };
    
        // Простите уж, без денормализованных чисел
    
        // Оставим знак и мантиссу
        DoubleInt xMantissa = x;
        xMantissa.asInt &= (MANTISSA_MASK | SIGN_MASK);
        // И добавим туда стандартный нулевой порядок
        xMantissa.asInt |= EXPONENT_SHIFTED_ORIGIN;
    
        // Извлечём порядок
        int exponent = ((x.asInt & EXPONENT_MASK) >> EXPONENT_SHIFT) - EXPONENT_ORIGIN;
    
        std::cout << xMantissa.asDouble << "*2^" << exponent << std::endl;
    
        return 0;
    }
    Ответ написан
    1 комментарий
  • Почему у строк всегда одиноковый hashcode()?

    @Mercury13
    Программист на «си с крестами» и не только
    String str1 = "Hello";
    String str2 = "Hello";

    Тут одна и та же ссылка. Но даже если сделать их разными объектами, всё будет аналогично.

    Начнём с того, что такое хэш-код. Если объекты равны, их хэш-коды гарантированно равны. Если не равны — то хэш коды, скорее всего (но не обязательно!) не равны. А теперь — о том, что такое «равные объекты».

    Изначально равенство объектов проверяется просто: никакие два объекта не равны, объект равен самому себе и никому больше. В таком случае естественно каким-то образом построить хэш-код из адреса.Для строк это не так, и функция hashCode() переписана, чтобы учитывала данные внутри, а не адрес.

    (Почему говорю «каким-то образом» — при определённом устройстве хэш-таблицы, если брать просто адрес, часть гнёзд будут простаивать. Так что устройство хэш-функции и хэш-таблицы надо согласовать, чтобы таблица заполнялась равномерно.)
    Ответ написан
    6 комментариев
  • Почему после вызова деструктора unordered_map перестаёт работать?

    @Mercury13
    Программист на «си с крестами» и не только
    Как в анекдоте (явно времён 70-х, когда между Гондурасом и Сальвадором была Футбольная война).
    — Что-то меня беспокоит Гондурас.
    — Так не чеши его.

    Вызов деструктора каскадно вызовет деструкторы всех полей, и это приведёт к тому, что на месте u_m будет мусор вроде nullptr и висячих указателей.

    Автодеструкторы — важнейшая фишка Си++, отличающая его от других языков, и явный вызов деструктора нужен крайне редко, когда мы хотим чуть более ручное управление памятью. Вот пример из нашего проекта. Есть выделенный кусок памяти, и мы хотим уничтожить там объект и на его месте создать новый, не отдавая-выделяя память. Считаем, что объекты одинаковые, иначе вся магия пропадёт.
    wiTile->~WiTile();
    new (wiTile) WiTile(client(), icons, clazz, tileSettings(i));

    В проекте на сотни тысяч строк я нашёл 34 таких места в библиотеках, в основном RapidJson, и три места собственно в программе.

    Если хотите полностью очистить — делайте отдельную функцию clear.

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

    @Mercury13
    Программист на «си с крестами» и не только
    testFuncTemplate(a, b, func<T>)
    testFuncTemplate(a, b, func<decltype(a)>)
    Ответ написан
    Комментировать
  • Qt: как привязать popup-окно к компоненту?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    616c1cffb8c40810341186.png
    Раз эти товарищи не сподобились сделать как надо — то приходится поступать для каждого случая по-особенному.
    Ответ написан
    Комментировать
  • Как можно (через Qt или WinAPI) узнать направление ClearType: RGB/BGR/другое?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    https://docs.microsoft.com/en-us/windows/win32/api...
    В Qt нет, посмотрел исходники — либо часть Chromium, либо не выглядывает наружу.
    Ответ написан
    Комментировать
  • Что такое точка доступа Wi-fi?

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

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

    @Mercury13
    Программист на «си с крестами» и не только
    Tony сказал правильно, но есть ещё одна вещь.
    CreateThread использовать ЗАПРЕЩАЕТСЯ. Точнее, можно — но для этого нужно знать, что делаешь. А так для прикладного прогера правило — надо перевести библиотеку времени выполнения в многопоточный режим, и для этого вызвать аналог из этой самой библиотеки. В Си++ для этого используется функция beginthreadex(), в Delphi — BeginThread.
    Ответ написан
    Комментировать
  • Стоит ли плагину доверят писать unit-тесты?

    @Mercury13
    Программист на «си с крестами» и не только
    Проверим один тест.
    // Какую концепцию проверяем?
       // Это не просто проверка функции ListAll, это проверка какой-то концепции кода
       // Варианты.
       // 1. Пустой listAll() даёт пустой список.
       // 2. Непустой listAll() даёт непустой список.
        void testListAll() {
            ArrayList<Product> productList = new ArrayList<Product>();
            // Проводим поиск в списке — что в этот список вносится?
            // И не будет ли физической зависимости тестов друг от друга?
            // И для чего вообще нужен этот search, если мы listAll тестируем?
            // Что такое ProductRepository и он вообще проверен?
            when(this.productRepository.search((String) any())).thenReturn(productList);
            // Ну, хорошо.
            List<Product> actualListAllResult = this.productService.listAll("Keyword");
            // Отказ, они не same: первый мы только что создали, а второй откуда-то пришёл.
            assertSame(productList, actualListAllResult);
            // Получается, что концепция — поиск, когда ничего не находится?
            assertTrue(actualListAllResult.isEmpty());
            verify(this.productRepository).search((String) any());
            // Получается, единственная концепция, которую мы тестируем,— поиск в пустом списке даёт пустоту
            // (и та некорректная из-за assertSame).
            assertTrue(this.productService.getAll().isEmpty());
        }


    Ну что, понятно, что или фтопку такие инструменты, или нужно их серьёзно осваивать, прежде чем будут приносить хоть какие-то результаты?
    Ответ написан
    Комментировать
  • Как лучше всего использовать ресурс батареи?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Прописать переход на зарядку процентах на 80…90 (обычно ≈95).
    2. Хоть иногда давать разряд-заряд.
    Вот и всё, что мы можем сделать.
    Ответ написан
    Комментировать
  • Как разбить числа по группам так, чтобы в группах находились близкие по значению числа?

    @Mercury13
    Программист на «си с крестами» и не только
    Это называется кластеризация, и самый ходовой метод для неё — K-means.
    Ответ написан
    2 комментария
  • Можно ли сделать код, который, если constexpr-выражение true, выдаст предупреждение?

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

    [[maybe_unused]] byte debugWarning = SIMULATE_CHANGED_HORIZON * 1000;


    В случае false компиляция пройдёт гладко. В случае true преобразование 1000 → byte выдаст предупреждение.
    Ответ написан
    Комментировать
  • Код не проходит проверку по времени, как ускорить?

    @Mercury13
    Программист на «си с крестами» и не только
    Нужно использовать тип данных «словарь» (в Си++ std::map/unordered_map), а не прямой поиск.
    Если в Питоне, как в PHP, массивы могут иметь любой индекс (ну не знаю я, не знаю) — вот вам и словарь.
    Ответ написан
    Комментировать
  • Почему char - 1 байт, а символьный литерал ('A') - 4?

    @Mercury13
    Программист на «си с крестами» и не только
    А теперь скажу правильный ответ.
    В Си символьный литерал имеет тип int и потому его sizeof 4 байта.
    В Си++ у него тип char и 1 байт. Потому те, кто создавал CPP-файл, проблемы не видели. Очевидно, связано с перегрузкой функций: как-то не хочется, чтобы в foo('A') вызывалась версия для int.
    #include <stdio.h>
    
    int main()
    {
        int sz = sizeof('A');  // латинское
        printf("sz = %d\n", sz);
        return 0;
    }

    Си: 4
    Си++: 1

    При написании char test='A' на стеке будет 1 байт (+выравнивание). Здесь Си, грубо говоря, проводит преобразование типа — прямо при компиляции. Если написать char test=L'Й', сообщит, что преобразование при компиляции ushort→char обрежет результат с 1049 до 25.
    Ответ написан
    Комментировать
  • Сложность алгоритмов для определения подстроки в строке?

    @Mercury13
    Программист на «си с крестами» и не только
    H = |haystack|, n = |needle|, a — размер алфавита.
    Примитивный алгоритм: предобработки нет, работа в среднем 2H, максимум O(Hn).
    Типичные быстрые алгоритмы: предобработка O(n) или O(n+a), работа в среднем <H, максимум O(Hn).
    Автоматные алгоритмы: предобработка O(na) или O(n+a), работа =H.
    Существуют СТРАШНЫЕ алгоритмы с работой в среднем <H и максимум O(H), где применяются — не знаю.
    Если нужно проводить несколько поисков одной «иголки» в разных «стогах», нужна всего одна предобработка.
    Ответ написан
    Комментировать
  • Как работает Hmac?

    @Mercury13
    Программист на «си с крестами» и не только
    HMAC — это так называемая имитовставка.
    То есть нечто среднее между хэш-функцией и электронной подписью.
    Тот, кто изменил сообщение и не знает ключа, НЕ МОЖЕТ подделать имитовставку — в отличие от хэш-функции.
    Но ключ подписи и проверки ОДИН И ТОТ ЖЕ — в отличие от электронной подписи.

    В современных веб-службах имитовставка используется для одного из вариантов аутентификации: сообщения закрыты прочным транспортным протоколом, но нет возможности проверить, тот ли человек на другом конце провода. Для этого подписываем всё тело запроса, и сервер, владеющий тем же ключом, сможет убедиться, что запрос сформирован нужным человеком.
    Ответ написан
    7 комментариев
  • Какие есть в Qt способы синхронизировать кусок кода с интерфейсным потоком?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    К сожалению, только сигналы — и ключевое слово BlockingQueuedConnection.
    А всё остальное — это как сделать синхроблок рядом с процедурой, а сигнал-слот — где-нибудь в главном окне. Скажем, так.

    class AsyncSimpleContext {  // интерфейс
    public:
      virtual void syncExec(const Runnable& body) = 0;
      template <class Body>
      void syncExecT(const Body& body); // тело упущу, тут всё стандартно,
                                             // идиома «виртуальный шаблон»
    }
    
    class FmMain : public AsyncSimpleContext
    {
      // Разрешите не писать реализацию syncExec — тут всё просто:
      // в конструкторе соединить сигнал со слотом методом BlockingQueuedConnection
      // в syncExec проверить id потока и или вызвать прямо, или возбудить сигнал.
    signals:
       void sigSyncExec(const Runnable&);
    private slots:
       void slotSyncExec(const Runnable&);
    }


    …и передавая куда-нибудь как-нибудь интерфейс AsyncSimpleContext, мы можем синхронизировать что-то с интерфейсом.
    Ответ написан
    Комментировать
  • Что значит после класса?

    @Mercury13
    Программист на «си с крестами» и не только
    Шаблонный класс.
    Гугли «Java Generics»

    String — Input parameter type
    Integer — progress report type
    String — result parameter type
    Ответ написан
    Комментировать
  • Как запустить код Си в проекте С++?

    @Mercury13
    Программист на «си с крестами» и не только
    не удается преобразовать 'char*' в 'int*' для аргумента '1' в 'int

    Как правило, ошибка. Функция хотела указатель на 4-байтовые слова — а мы передаём ей указатель на байты.
    Если очень нужно рассматривать int* как char* (например, работаем не с данными какого-то определённого типа, а просто с байтами в памяти) — используйте reinterpret_cast.

    недопустимое преобразование из 'int*' в 'int'

    Почти всегда ошибка. Функция хотела число — а мы ей передаём ей указатель.
    Если реально по какой-то причине нужно значение указателя воспринимать как число — используйте reinterpret_cast.

    Возможен и другой вариант — вы просто упустили операцию «разыменовать» *.

    warning: narrowing conversion of '143' from 'int' to 'char' inside

    Точно ошибка — 143 не вписывается в char (−128…127). Если очень надо, используй static_cast.

    Покажите лучше код, и я устрою ему ревизию.
    Ответ написан
    Комментировать