Ответы пользователя по тегу C
  • Как собрать проект с GitHub?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Думаю, только его собрать не получится, т.к. есть зависимости от рута проекта (сборка сверху вниз идет).

    Для сборки надо использовать Makefile - это файл, в котором описано то как надо собирать. В твоем случае, надо только запустить make miyoomini из корня репозитория. Можешь заметить, что в той директории, что ты указал, он (Makefile) тоже есть, но зависит от верхнеуровневых.

    Так как ты под виндой, то единственный совет - используй WSL. Тебе надо использовать линуксовские утилиты, это делать проще на линуксе (хотя бы таком). Дополнительно, в процессе установки используется докер - это тоже учитывай.

    Как прошить Miyoo Mini не подскажу, не занимался таким
    Ответ написан
    4 комментария
  • Почему clang выдает такой ассемблерный код?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Зависит от окружения/флагов/версии
    Но я здесь вижу:
    1. Именованная константа со своим адресом (PIC)
    2. Простое число

    В первом случае необходимо использовать регистр (временное хранилище), т.к. нельзя копировать из памяти в память - надо оперировать регистрами
    Ответ написан
  • Что отвечает за предотвращение нежелательной записи в text секцию?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Я вижу тут 2 варианта:

    1. Адрес функции не выровнен, это и вызывает SIGBUS
    2. Тут баг с назначением номеров сигналов и на самом деле тебе поступает SIGSEGV, т.к. адрес неверный

    Второе прямо описывается в man'е man 7 signals


    BUGS
    For example, an invalid memory access that causes delivery of SIGSEGV
    on one CPU architecture may cause delivery of SIGBUS on another archi‐
    tecture, or vice versa.


    Отвечая на твой вопрос, что предотвращает запись в секцию .text - флаги секций. У каждой секции есть свои флаги, которые отвечают за возможности работы с этими секциями.
    Для этого можно использовать objdump -h <executable>. В частности, я запустил и вот такой вывод появился для бинарника

    14 .plt.sec      00000020  0000000000001060  0000000000001060  00001060  2**4
                      CONTENTS, ALLOC, LOAD, READONLY, CODE
     15 .text         00000118  0000000000001080  0000000000001080  00001080  2**4
                      CONTENTS, ALLOC, LOAD, READONLY, CODE
     16 .fini         0000000d  0000000000001198  0000000000001198  00001198  2**2
                      CONTENTS, ALLOC, LOAD, READONLY, CODE


    Можешь заметить, что .text помечен как READONLY

    Все-таки можно изменить

    Есть системный вызов ptrace, который вообще-то может изменить секцию кода, но проблема в том, что он работает с инструкциями и работать можно только с дочерним процессом. Грубо говоря, выступешь в роли отладчика.
    Поэтому можешь считать, что .text не изменить
    Ответ написан
  • Что возвращает присваивание пробела целочисленной переменной?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Во-первых, это не строка, а символ - char. Грубо говоря - байт. Байт - это число.
    У каждого символа есть свой код. В данном случае используется ASCII кодировка и в ней пробел имеет код 32 (десятичный).
    Ты присваиваешь char переменной int - тут неявный каст (приведение типов). Потерь данных нет, т.к. int принимает больше значений (он 4 байтный).
    Таким образом, в этой строке переменной integer присваивается значение 32.
    Прочитай про типы данных
    Ответ написан
    1 комментарий
  • Почему из-за cfgmgr32 exe стал больше на 32 мб?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Потому что .lib на винде - это статическая библиотека. Ты ее полностью к себе присоединил полностью, со всем ее кодом, функциями, переменными и т.д.
    За инфру винды не шарю, но может есть версия этой либы динамическая. Например, cfgmgr32.dll.

    P.S. я первый раз увидел, чтобы зависимости добавляли с помощью pragma. Это windows-specific ?
    Ответ написан
  • Почему GCC не видит встроенную атомарную операцию?

    AshBlade
    @AshBlade Автор вопроса
    Просто хочу быть счастливым
    Разобрался.
    Есть 2 замечания:
    1. Поближе посмотрел на сигнатуру

    bool __atomic_compare_exchange (type *ptr, type *expected, type *desired, bool weak, int success_memorder, int failure_memorder)


    Короче говоря, мне нужно было передавать не указатели, а указатели на указатели. Исправил:

    if (__atomic_compare_exchange(&l.head->next,  (struct entry**)NULL, &new_next, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))


    Но потом начал ловить SEGFAULT. И тут пришел к 2 замечанию

    2. Не заметил следующего в документации:

    This built-in function implements an atomic compare and exchange operation. This compares the contents of *ptr with the contents of *expected. If equal, the operation is a read-modify-write operation that writes desired into *ptr. If they are not equal, the operation is a read and the current contents of *ptr are written into *expected. weak is true for weak compare_exchange, which may fail spuriously, and false for the strong variation, which never fails spuriously. Many targets only offer the strong variation and ignore the parameter. When in doubt, use the strong variation.


    Т.е. если значение во 2 аргументе не равно значению из 1, то (!!!) по месту указателя 2 записывается полученное из указателя 1 значение. А у меня там был NULL (конец списка обозначается NULL). Заменил на корректно выделенный элемент списка и все заработало

    int main(int argc, char const *argv[])
    {
        struct list l;
    
        l.head = (struct entry *)malloc(sizeof(struct entry));
        l.head->next = NULL;
        l.head->value = 123;
        struct entry *old_next = (struct entry *)malloc(sizeof(struct entry));
        old_next->next = NULL;
        old_next->value = 555;
        l.head->next = old_next;
    
        struct entry *new_next = (struct entry *)malloc(sizeof(struct entry));
        new_next->value = 444;
        new_next->next = NULL;
        if (__atomic_compare_exchange(&l.head->next, &old_next, &new_next, 1, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
        {
            printf("ok\n");
            printf("success: next = %d\n", l.head->next->value);
        }
        else
        {
            printf("failed\n");
        }
    
        return 0;
    }


    Не хочу возиться со всякими dummy узлами, поэтому буду использовать __sync_bool_compare_and_swap. Вот такой код сработает:
    int main(int argc, char const *argv[])
    {
        struct list l;
    
        l.head = (struct entry *)malloc(sizeof(struct entry));
        l.head->next = NULL;
        l.head->value = 123;
    
        struct entry *new_next = (struct entry *)malloc(sizeof(struct entry));
        new_next->value = 444;
        new_next->next = NULL;
    
        if (__sync_bool_compare_and_swap(&l.head->next, (struct entry *)NULL, new_next))
        {
            printf("ok\n");
            printf("success: next = %d\n", l.head->next->value);
        }
        else
        {
            printf("failed\n");
        }
    
        return 0;
    }


    UPD: спасибо res2001, разобрался лучше. итоговый вариант

    #include <stdatomic.h>
    
    int main(int argc, char const *argv[])
    {
        struct list l;
    
        l.head = (struct entry *)malloc(sizeof(struct entry));
        l.head->next = NULL;
        l.head->value = 123;
    
        struct entry *new_next = (struct entry *)malloc(sizeof(struct entry));
        new_next->value = 444;
        new_next->next = NULL;
        struct entry *tmp = NULL;
        if (atomic_compare_exchange_strong(&l.head->next, &tmp, new_next))
        {
            printf("ok\n");
            printf("success: next = %d\n", l.head->next->value);
        }
        else
        {
            printf("failed\n");
        }
    
        return 0;
    }


    Просто надо создать переменную указатель, которой присвоить NULL. Также использовал atomic_compare_exchange_strong из stdatomic вместо расширения GCC - он под капотом использует __atomic_* вместо устаревшего __sync_*
    Ответ написан
    1 комментарий
  • Возможно ли сделать nested enum c/c++?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Если мы говорим про C, то так делать нельзя:
    1. Вложенные в enum определения делать нельзя - это ограничение самого синтаксиса (дока)
    2. Для использования перечислений не надо указывать само название перечисления. Т.е. не OBJ::SOMETHING, а просто SOMETHING. Т.е. видимость глобальная и нельзя дублировать названия, даже для разных enum

    В случае C++ аналогично. Есть хак - использование неймспейсов или структур для топ левела, но не в твоем случае - ты хочешь топ левел перечислениям значения задавать

    На мой взгляд тут решение:
    1. Разбить их на различные перечисления
    2. Добавить каждому префикс
    enum OBJ = 0 {
           Default = 0,
           Something_Something1 = 1,
           Something_Something1 = 2,
           Something = 7
    };
    Ответ написан
    Комментировать
  • Как устранить ошибку конверсии при использовании битовых полей?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Я протестировал это (со встроенным (addr >> 12) * 0xFFFFu) у себя на GCC (версия 11.4.0) и clang (14.0.0) на x86_64. Дополнительно в нескольких онлайн компиляторах. И на MinGW (версия 6.3.0).
    Нигде предупреждений подобных не встречал.
    Скорее всего это особенность версии компилятора/платформы.
    Ответ написан
  • Как следать процерку на ввод целых чисел?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Можно использовать strtol
    int parse(char* str, long* result) {
        char *end = NULL;
        *result = strtol(str, &end, 10);
        if (str == end || *end != '\0' || errno == ERANGE) {
            return -1;
        }
        return 0;
    }


    Пример:
    int main() {
        long value;
        if (parse("12313", &value)) {
            printf("Ошибка");
        } else {
            printf("Результат: %ld", value);
        }
    }
    // 123 -> Результат: 123
    // 123.0 -> Ошибка
    Ответ написан
    Комментировать
  • Что считать корректным вводом целого числа?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Целое число - это все натуральные, им противоположные и 0 - без всяких дробей, экспонент и т.д.
    Используй это определение, не усложняй себе жизнь
    Ответ написан
    Комментировать
  • Как в С можно сделать реагирование на клавишу клавиатуры без ожидания обязательного ввода (без использования стандартных библиотек)?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Можно запустить фоновый поток: он читает ввод и при получении Q/q выставляет флаг окончания.
    Псеводкод:

    int should_stop = 0;
    
    void keyboard_processor() {
         while (should_stop != 1) {
               char input = get_input();
               if (input == 'q' || input == 'Q') {
                      should_stop = 1;
                      break;
               }
         }
    }
    int main() {
        start_thread(keyboard_processor);
        while (should_stop != 1) {
              do_work();
        }
    }
    Ответ написан
  • Контринтуитивный синтаксис объявления нескольких переменных одного типа?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Объясните, что я недопонимаю?

    Все правильно понимаешь. Привыкай.

    P.S. вот поэтому и рекомендуют * писать рядом с переменной, а не у типа - const char *var , а не const char* var
    Ответ написан
    1 комментарий
  • Как создают интерфейсы в программах?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Самый низкий уровень - системные вызовы:
    Это WinAPI, X11 и т.д. Я не десктоп разработчик, но сейчас мало кто ими пользуется.

    Дальше идут фреймворки, потроенные вокруг них:
    Это wxWidgets, WTL (Windows Template Library)

    И на самом верху - полноценные языки разметки/программирования:
    Qt, XAML, Electron

    Дополнительно, никто не мешает свой фреймворк написать оконный - поверх существующих WinAPI, либо через графический фреймворк (SDL, например)
    Ответ написан
    1 комментарий
  • Почему нет записи о printf в секции .plt.dyn?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    Но там запись о функции puts, а не printf.

    Это уже оптимизация компилятора. Возможно ты не передаешь printf никаких аргументов и он решил, что проще вызвать puts.
    Такое поведение уже было описано вот тут:
    The C compiler gcc likes to use its knowledge of builtin functions to manipulate code. The version of gcc in NetBSD 4.0.1/macppc will simplify the printf statement to puts("Greeting, Earth!"); so the main function effectively calls puts(3) once and then returns 0.
    Ответ написан
    1 комментарий
  • Как сделать ввод через стандартный поток (stdin) и через файл?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    2 варианта:
    - Если аргументов вообще нет, то через poll (либо select) проверяешь событие доступности данных - SO
    - Некоторые Unix программы проверяют, что если передан дефис/тире -, то читать надо из stdin (учитывай)
    Ответ написан
    Комментировать
  • Что стоит учить с или c++ или c#?

    AshBlade
    @AshBlade Куратор тега C#
    Просто хочу быть счастливым
    Это 3 совершенно различных, с точки зрения целей, языка. Лучше пойми что ТЫ хочешь, а потом выбери
    Ответ написан
    Комментировать
  • Получение значения указателя в структуре которая является указателем?

    AshBlade
    @AshBlade
    Просто хочу быть счастливым
    struct SomeData {
      char* pointer;
    }
    
    ...
    
    SomeData* ptr;
    /* что нужно */
    char* ptr_ch = ptr->pointer;
    Ответ написан
    Комментировать