• Почему компилятор не генерирует конструктор по умолчанию в отдельной единице трансляции?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Почему компилятор не генерирует конструктор

    потому что нигде не написано, что он должен? Я вижу, что в коде генерируемом gcc инициализация таблицы виртуальных функций инлайнится по месту создания объекта, вне зависимости от опций оптимизации.
    Ответ написан
    1 комментарий
  • Почему можно не указывать virtual в файле реализации?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Почему можно не указывать virtual в файле реализации?

    Не то чтобы "можно не указывать". Нужно не указывать. Потому что так говорит стандарт.
    И потому что виртуальность функции -- это не свойство функции, а свойство класса которому она принадлежит. Код функции не зависит от того, виртуальная она или нет.
    Ответ написан
    4 комментария
  • Почему виснит программа на MPI?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Почему виснет программа на MPI?

    Потому что процесс с rank = 0 хочет послать VEC_SIZE сообщений, а процессы с rank > 0 обрабатывают каждый только по одному сообщению, после чего завершаются. Тебе нужно как-то объяснить исполнителям, сколько запросов они должны обработать перед завершением. Например так:

    if(rank == 0){
                    for(int i = 0; i < VEC_SIZE; i++){
                            …
                    }
                    for (int i = 1; i < size; ++i) {
                            int q = -1;
                            MPI_Send(&q, 1, MPI_INT, i, 0, MPI_COMM_WORLD);
                    }
            }else{
                    for (;;) {
                            int index;
                            MPI_Status status;
                            MPI_Recv(&index, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
                            if (index < 0)
                                    break;
                            …
                    }
            };


    Отдельно стоит сказать о том, что цикл который посылает задачу процессу и тут же ждёт результата от этого же самого процесса не имеет смысла с точки зрения улучшения производительности. Имеет смысл сначала разослать задания свободным исполнителям, а только после этого начинать ждать от них ответов.

    И ещё по мелочи:
    for(size_t i = 0; i < VEC_SIZE; i++){
                size_t num_process = (i % (size - 1)) + 1;
                MPI_Send(&i, 1, MPI_INT, static_cast<int>(num_process), 0, MPI_COMM_WORLD);

    размер size_t i может отличаться от размера int, подразумеваемого типом MPI_INT. Этот код точно будет работать неправильно на big-endian архитектурах с LP64 ABI.
    Ответ написан
    Комментировать
  • Как увеличить FPS в системе?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Как увеличить FPS в системе?

    Ты уже задавал этот вопрос в комментариях к предыдущему вопросу, там есть ответ:

    Основной способ стандартный -- не перерисовывать всё, если можно этого избежать.

    Нет нужды перерисовывать весь интерфейс в бэк-буфере, если ничего не изменилось кроме положения мыши. Указатель мыши вообще можно рисовать прямо во фрейм-буфере, когда он перемещается копировать маленький квадратик из бэк-буфера и рисовать стрелку в новом месте.
    Ответ написан
  • Почему не работает двойная буферизация?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    VIDEO_BUFFER_SEGMENT = 0xA000
    VIDEO_BUFFER_OFFSET = 0xFA00
    VIDEO_SEGMENT = 0xA000
    VIDEO_OFFSET = 0x0000

    как ты думаешь, сколько памяти в сегменте VIDEO_BUFFER_SEGMENT доступно начиная со смещения VIDEO_BUFFER_OFFSET и что там идёт дальше?

    Если в твоём коде сделать вот такие изменения, то всё работает:
    diff --git a/lib/video.inc b/lib/video.inc
    index 3a26f43e2f79..d7054e194da9 100644
    --- a/lib/video.inc
    +++ b/lib/video.inc
    @@ -3,8 +3,8 @@ VIDEO_INC equ 0
     
     include "memory.inc"
     
    -VIDEO_BUFFER_SEGMENT = 0xA000
    -VIDEO_BUFFER_OFFSET = 0xFA00
    +VIDEO_BUFFER_SEGMENT = 0x6000
    +VIDEO_BUFFER_OFFSET = 0x0000
     VIDEO_SEGMENT = 0xA000
     VIDEO_OFFSET = 0x0000
     VIDEO_SIZE_DB = 0xFA00
    @@ -79,11 +79,11 @@ macro video!flip {
            mov ax, VIDEO_SEGMENT
            mov bx, VIDEO_BUFFER_SEGMENT
            mov es, ax
    -       mov ds, ax
    +       mov ds, bx
            mov cx, VIDEO_SIZE_DB
            cld
            mov si, VIDEO_BUFFER_OFFSET
    -       xor di, VIDEO_OFFSET
    +       mov di, VIDEO_OFFSET
            rep movsb
            pop ds es
     }
    diff --git a/os.asm b/os.asm
    index 1949e95b4e99..e5ebb3d280aa 100644
    --- a/os.asm
    +++ b/os.asm
    @@ -91,9 +91,9 @@ kernel.routine.startup:
     kernel.routine.video:
            cli
            video!fill 0x4E
    -       ;video!window 30, 40, 100, 60, 0x1A, 0xFF, 13 , 0x1F
    -       ;video!cursor
    -       ;video!flip
    +       video!window 30, 40, 100, 60, 0x1A, 0xFF, 13 , 0x1F
    +       video!cursor
    +       video!flip
            sti
            ret
    Ответ написан
  • Как исправить движение мыши?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    mov al, [bp+12]
      mov bl, al
      mov cl, 3
      shl al, cl
    
      sbb dh, dh
      cbw
      mov dl, [bp+8]
      mov al, [bp+10]

    Этот кусок кода из обработчика перемещений мыши должен делать знаковое расширение 9-битных координат, но я вижу, что в существующем коде в обработчик перемещений всегда приходят нули в координатах x и y, а из-за этого знакового расширения отрицательные dx и dy всегда становятся равными -256. Если добавить вызов функции initialize (0xc205) прерывания 0x15 в mouse.init с 3-байтными пакетами:
    kernel.routine.mouse.init:
      push es bx
      int 0x11
      test ax, 4
      jz kernel.routine.mouse.init.error
      mov ax, 0xC205
      mov bh, 3
      int 0x15
      jc kernel.routine.mouse.init.error
      mov ax, 0xC203
      mov bh, MOUSE_RESOLUTION
      int 0x15
      jc kernel.routine.mouse.init.error

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

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Не работает деструктор

    "Не работает деструктор" -- это когда программу компилируешь, запускаешь, а деструктор не делает того, что в нём написано. У тебя же программа не компилируется. Из-за того, что в настройках компилятора стоит "трактовать предупреждения как ошибки" и "предупреждать о неэффективном коде С++". Ну и вдобавок, предупреждение тебе правильно говорит, что если ты не реализовал конструктор копирования и оператор присваивания для класса самостоятельно управляющего памятью, то жди проблем, когда начнёшь копировать объекты этого класса.
    Ответ написан
    6 комментариев
  • Как сделать сжатие и распаковку char* в C++ с помощью zlib?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    что я делаю не так?

    Несколько вещей. В compress_char ты сначала выделяешь strlen(source) байт для вывода, а потом находишь compSize, который может быть и больше чем strlen(source). Ты не возвращаешь compSize после вызова compress, а он может измениться. Ты возвращаешь только char*, как будто это строка, но это не строка, там могут быть нулевые байты.
    В uncompress_char почти те же самые ошибки. Плюс какая-то путаница между length, compSize и ucompSize. На вход uncompress в параметре compSize должен попасть настоящий размер сжатых данных, а не догадка о нём на основе вызова compressBound.
    Я бы поменял код как-то так:
    char* compress_char(const char* source, size_t *outCompSize, size_t *outUcompSize)
    {
        uLong ucompSize = strlen(source) + 1;
        uLong compSize = compressBound(ucompSize);
        char* bytes = malloc(compSize);
        compress((Bytef *)bytes, &compSize, (Bytef *)source, ucompSize);
        *outCompSize = compSize;
        *outUcompSize = ucompSize;
        return bytes;
    }
    
    char* uncompress_char(const unsigned char source[], size_t inCompSize, size_t inUcompSize)
    {
        uLong ucompSize = inUcompSize;
        uLong compSize = inCompSize;
        char* message = malloc(ucompSize);
        uncompress((Bytef *)message, &ucompSize, (Bytef *)source, compSize);
        return message;
    }
    
    void foo(void)
    {
        size_t a, b;
        char *p = compress_char("{\"a2\":\"b\"}", &a, &b);
        char *p1 = uncompress_char(p, a, b);
        printf("%s, %zd -> %zd\n", p1, b, a);
    }


    Плюс ты не обрабатываешь коды возврата из compress/uncompress.
    Ответ написан
    Комментировать
  • Как конвертировать 8-битное bmp изображение в бинарный файл?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    У меня есть 8-битный bmp, 320х200 пкс. Мне нужно форматировать его в бинарный файл (1 байт = один пиксель) для линейного буфера по адресу 0хА0000.
    Вот целевая палитра

    Для этого надо понять что такое палитра и что твоя задача звучит как два преобразования: 1) из байта в битмапе -- в цвет, а потом 2) из цвета в байт твоём линейном буфере.
    Для преобразования 1) нужно взять RGB из палитры битмапа по индексу в байте из битмапа.
    Для преобразования 2) нужно найти индекс элемента в целевой палитре, RGB в котором наиболее близки к нужному цвету.
    Ответ написан
    2 комментария
  • Получение доступа к регистру rip x86-64 архитектура?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    как получить доступ к этому регистру?

    lea (%rip), %rax (в синтаксисе at&t) получает адрес следующей инструкции
    Ответ написан
    2 комментария
  • Статическое подключение zlib в .so?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    У меня есть код на C++, который использует zlib. Я хочу на линуксе его скомпилировать в .so библиотеку, но чтобы команда ldd не показывала libz.so или libz.so.1 (чтобы zlib был встроен в .so).

    Ключами линковщика -Bstatic и -Bdynamic можно переключать режим линковки библиотек:
    g++ -shared foo.cc -o libfoo.so -Wl,-Bstatic -lz -Wl,-Bdynamic

    Но если так сделать, то можно заметить, что не всякую статическую библиотеку можно прилинковать к .so, а только такую, объектники которой собраны с флагом -fpic.
    Ответ написан
  • Как правильно посчитать время выполнения fread/fwrite (gcc)?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Как правильно посчитать время выполнения fread/fwrite
    Нужно посчитать время чтения и время записи одинакого размера блока данных на диск.
    Причем, время момента, когда данные окажутся на диске

    fread/fwrite -- плохой выбор для этого, потому что это функции библиотеки C, т.е. между ними и ядром ОС ещё один слой абстракции.

    Я правильно понимаю, что fclose(f) закрывает файловый дескриптор f после того как данные записаны на диск?

    Неа. Тот кто читает маны должен приучаться делать это до конца. В случае fclose -> fflush там написано следующее:
    Note that fflush() flushes only the user-space buffers provided
    by the C library.  To ensure that the data is physically stored
    on disk the kernel buffers must be flushed too…


    нужна функция get_time_func()

    Стандартный способ -- clock_gettime, в качестве clockid думаю подойдёт CLOCK_MONOTONIC_RAW.
    Ответ написан
  • Какие права нужны для создания сетевых интерфейсов linux?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    создать интерфейсы приложение не может т.к. не хватает привилегий.

    А если внимательно прочитать лог, то можно увидеть sudo: not found. Т.е. скрипт рассчитывает выполнить привилегированную часть с помощью sudo, но его (sudo) нет.

    Полагаю, необходимо дать права пользователю 1000:1000 на хосте, не совсем понятно какие и на какие файлы.

    Вообще для манипуляций с сетевыми ресурсами нужна capability CAP_NET_ADMIN, её отсутствие нельзя восполнить никакими разрешениями на файлах.
    Ответ написан
    Комментировать
  • Как работает %[^\n]s?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Верно ли я понимаю, что первый scanf читает поток и останавливается на \n , после чего каждый последующий вызов scanf начинает чтение с этого же символа (\n) и, следовательно, моментально останавливается

    Понимаешь верно. Вдобавок форматная строка %[^\n]s содержит символ s который никогда не заматчится, потому что %[^\n] останавливается на символе '\n'. Логично было бы заменить её на %[^\n]%*c чтобы работало так, как было задумано.
    Ответ написан
    3 комментария
  • Как создать такой вывод в bash script?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    С чего начинать разбираться?

    man 7 inode -- обзор того, какие атрибуты есть у файлов
    man 1 mkdir -- создавать каталоги и назначать им разрешения
    man 1 touch -- создавать файлы и менять даты файлам и каталогам
    man 1 chmod -- менять разрешения файлам и каталогам
    man 1 ln -- создавать символьные ссылки
    Ответ написан
    7 комментариев
  • Почему scanf считывает значение только первой переменной?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    while (scanf("%f %f %f", &a, &b, &c) != 1 || ...

    В приведённом коде нет определений a, b и c. Они должны иметь тип float, чтобы формат %f scanf работал правильно.

    если сначала ввести 1 2 3, то приложение выведет "Ошибка. Введите снова: "
    как это исправить?

    scanf возвращает число успешно отсканированных полей, возвращаемое scanf значение надо сравнивать с 3 в условии цикла.
    Ответ написан
    Комментировать
  • Как выводить русские символы в си?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    как это работает

    Поскольку русский -- не часть ASCII, работает это по-разному в зависимости от кодировки. Если предположить, что исходник в UTF-8, то русские символы закодированы двумя байтами, а %c выводит только один. Если на одном выведенном байте остановиться -- получится фигня с вопросом. Но если вывести подряд все байты многобайтового символа -- получится этот символ.

    как исправить

    вариантов несколько. Самый простой -- выводить строки целиком. Если надо выводить посимвольно, можно узнавать количество байт в представлении одного символа функцией mblen, типа того:
    #include <locale.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    int main() {
      char *a = "Привет, мир";
      int s;
      setlocale(LC_ALL, "");
      for (; *a != '\0'; a+=s) {
        s = mblen(a, strlen(a));
        printf("%.*s-", s, a);
        }
        return 0;
    }

    Здесь setlocale нужен для того, чтобы mblen понял, в какой кодировке символы на входе. Локаль в момент выполнения должна быть совместимой с кодировкой исходника в момент компиляции, если это условие не выполняется, работать будет неправильно.

    Ещё вариант -- работать не с многобайтовой кодировкой а с wchar_t:
    #include <locale.h>
    #include <stdio.h>
    #include <stddef.h>
    
    int main() {
      wchar_t *a = L"Привет, мир";
      setlocale(LC_ALL, "");
      for (; *a != '\0'; a++) {
        printf("%lc-", *a);
        }
        return 0;
    }

    Здесь setlocale нужен для другого: он говорит внутренностям printf в какую локаль выполняется вывод чтобы в неё конвертировать wchar_t. Если локаль во время выполнения не будет соответствовать кодировке исходника, код всё равно будет работать.
    Ответ написан
    2 комментария
  • Bsd-socket. Почему бесконечное чтение при http запросе?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    При повторной итерации read, по идее, должен вернуть 0, так как все прочитано

    Неа, не так это работает. 0 из read возвращается в одном единственном случае: если та сторона закрыла сокет на передачу и все посланные ею данные получены. В противном случае (сокет не закрыт) поведение зависит от настроек сокета: синхронный сокет при попытке чтения может заблокироваться в функции read или вернуть из неё -1 (и установить errno, например, в EINTR). Асинхронный сокет вернёт из read -1 и установит errno в EAGAIN или EWOULDBLOCK.
    Ваш HTTP-сервер наверняка оставляет соединение открытым после того как прислал ответ на первый запрос, это можно понять по наличию заголовка Connection: Keep-Alive или отсутствию заголовка Connection: close в его ответе если это HTTP/1.1. Его можно попросить закрыть соединение после ответа, послав запрос с заголовком Connection: close или можно избежать блокировки в read прочитав только данные ответа размер которых прислан в заголовке ответа Content-Length.
    Ответ написан
    2 комментария
  • Почему возникла ошибка при сортировке?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    В чём ошибка?

    В том, что функция qSort при попытке сортировки массива одинаковых значений все их сносит в массив right, оставляя массив left пустым. Циклический алгоритм на этом месте зациклился бы, а рекурсивный с не-хвостовой рекурсией выходит за ограничение размера стека.
    Ответ написан
    Комментировать
  • FASM Что не так с процедурой?

    jcmvbkbc
    @jcmvbkbc
    "I'm here to consult you" © Dogbert
    Что не так с процедурой?

    stdcall test_proc, 11
    …
    proc test_proc, ms
    …
    mov rbx, qword ptr ms


    ABI вызова не совпадает с ABI процедуры: 64-битный stdcall передаёт первый параметр в rcx, а test_proc ожидает его на стеке, в чём легко убедиться пропустив результат через objdump:

    403004:       48 c7 c1 0b 00 00 00    mov    $0xb,%rcx
    40300b:       e8 19 00 00 00          callq  0x403029
    …
    40307b:       48 8b 5d 10             mov    0x10(%rbp),%rbx
    Ответ написан
    Комментировать