Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Это потому что sh_pulse вызывается в коде раньше, чем объявляется - отсюда и проблема implicit declaration.

А необъявленные функции вроде как считаются по умолчанию возвращающими int, отсюда и "починка" помогает.

Либо выстраивайте последовательность функций так, чтобы "верхние" никогда не использовали "нижние", либо, что правильнее, для каждой функции в начале файла их дополнительно объявляйте. В идеале - как static, если они не вызываются из других модулей.
NStorm
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Re: Вопросы по С/С++ (СИ)

Сообщение NStorm »

[uquote="Shuspano",url="/forum/viewtopic.php?p=3835922#p3835922"]d:\avr\hc164.c:30:3: note: previous implicit declaration of 'sh_pulse' was here
sh_pulse();
^[/uquote]
Уже ответили, но если не понятно, после #include'ов напишите строку void sh_pulse(void); именно с ; в конце, без самого тела функции и заработает всё. Кстати void в скобках можно не писать везде. void sh_pulse()

И еще вопрос: пытался делать это под линуксом (debian 10 x64), там AVR-GCC (установленный через APT) выдает типа:
Скорее всего в опциях компиляции не указали модель МК ключиком -mmcu
Аватара пользователя
Shuspano
Грызет канифоль
Сообщения: 270
Зарегистрирован: Вс окт 20, 2019 13:03:56

Re: Вопросы по С/С++ (СИ)

Сообщение Shuspano »

[uquote="WiseLord",url="/forum/viewtopic.php?p=3835924#p3835924"]Это потому что sh_pulse вызывается в коде раньше, чем объявляется.[/uquote]
NStorm писал(а):Кстати void в скобках можно не писать везде. void sh_pulse()
Спасибо, буду знать.
Когда-то достаточно давно, пытался ковырятся с Borland C 3.1, помню он очень ревностно относился к синтаксису.
NStorm
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Re: Вопросы по С/С++ (СИ)

Сообщение NStorm »

Ну нынче если вы определяете (не путать с объявлением, о котором я выше написал) функцию, то f() { ... } = f(void) { ... }. А вот с объявлением ( f(); ) могут быть нюансы, если потом определение не void. Я что-то сразу об этом не подумал. Если привыкли писать f(void) то и фиг с ним, проблема не в этом )
Аватара пользователя
uldemir
Друг Кота
Сообщения: 7359
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Re: Вопросы по С/С++ (СИ)

Сообщение uldemir »

Подскажите как сделать. Тоже рисую велосипед меню. И у меня есть такая структура:

Код: Выделить всё

typedef struct {
	unsigned char todisplay[16];
				int *variable;
		 datatype_t datatype;
} menuitem_t;
И вот мне захотелось, чтобы int* variable иногда являлся адресом void функции без параметров, которую я хочу запустить на выполнение.
как написать функцию, которой если передать int *variable, вызвала бы на выполнение функцию по адресу этой variable?

Код: Выделить всё

void FreeRun(void);

menuitem_t menu[] = {
...
{"Free Run", (int*)FreeRun, execute},
...
}
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Аватара пользователя
da-nie
Говорящий с текстолитом
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение da-nie »

как написать функцию, которой если передать int *variable, вызвала бы на выполнение функцию по адресу этой variable?
Можно запустить на выполнение, например, так:

void Test(void)
{

};

menuitem_t menuitem;
menuitem.variable=(int*)Test;

typedef void (*func_ptr)(void);

((func_ptr)menuitem.variable)();
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Аватара пользователя
uldemir
Друг Кота
Сообщения: 7359
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Re: Вопросы по С/С++ (СИ)

Сообщение uldemir »

Написал так:

Код: Выделить всё

void do_execute(int* addr) {
	void (*Task)(void);
	Task = (void (*)(void))addr;
	(*Task)();
}
Вррроде работает... сейчас попробую через typedef.

О, так даже проще! Спасибо.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Вот такой пример:
Спойлер

Код: Выделить всё

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>

typedef enum {
    var_int,
    var_char,
    execute,
} datatype_t;

typedef struct {
    unsigned char todisplay[16];
    void *variable;
    datatype_t datatype;
} menuitem_t;

void FreeRun(void)
{
    printf("Hello FreeRun\n");
}

int height = 3;
char hour = 10;

typedef enum {
    HEIGHT,
    FREE_RUN,
    HOUR,
} menuidx_t;

menuitem_t menu[] = {
    [HEIGHT]    = {"Height", &height, var_int},
    [FREE_RUN]  = {"Free Run", FreeRun, execute},
    [HOUR]      = {"Hour", &hour, var_char},
};

typedef void (*execute_func)(void);


void handleMenu(menuidx_t idx)
{
    switch (menu[idx].datatype) {
    case var_int: {
        int *var = (int *)(menu[idx].variable);
        (*var)++;
    }
    break;
    case var_char: {
        char *var = (char *)(menu[idx].variable);
        (*var)--;
    }
    break;
    case execute: {
        execute_func func = (execute_func)(menu[idx].variable);
        func();
    }
        break;
    }
}

int main()
{
    printf("----Before:\n");
    printf("Height: %d\n", height);
    printf("Hour: %d\n", hour);

    handleMenu(HEIGHT);
    handleMenu(FREE_RUN);
    handleMenu(HOUR);

    printf("----After:\n");
    printf("Height: %d\n", height);
    printf("Hour: %d\n", hour);

    return 0;
}
Выводит:
Спойлер

Код: Выделить всё

----Before:
Height: 3
Hour: 10
Hello FreeRun
----After:
Height: 4
Hour: 9
NStorm
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Re: Вопросы по С/С++ (СИ)

Сообщение NStorm »

uldemir, через typedef (void *) лучше, что хотя бы если вы перепутаете и передадите указатель не на такой тип, то хотя бы warning компилятор сделает. А то передадите так int i; ... &i и капец ) А WiseLord более правильное решение подсказал, когда если по указателю ссылка может передаваться и на переменную и на функцию - то надо дополнительно передавать тип.
А вообще это по сути callback получается.
Аватара пользователя
da-nie
Говорящий с текстолитом
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение da-nie »

когда если по указателю ссылка может передаваться и на переменную и на функцию - то надо дополнительно передавать тип.
Можно сделать функтор (ну или лямбду, которая им и является по сути), который будет хранить указатель на int и возвращать его при вызове. И другие функторы, которые ничего хранить не будут, а будут при вызове делать свою работу и возвращать, например, NULL. Но тогда нужен будет уже C++, а тут C. Впрочем, это уже из разряда извращений в данном случае. :)
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Аватара пользователя
uldemir
Друг Кота
Сообщения: 7359
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Re: Вопросы по С/С++ (СИ)

Сообщение uldemir »

У меня примерно так и сделано было:

Код: Выделить всё

                        switch (item[select].datatype) {
                            case decimal:
                                mode = edit_mode;
                                editnum = 5; break;
                            case hex:
                                mode = edit_mode;
                                editnum = 4; break;
                            case hex32:
                                mode = edit_mode;
                                editnum = 8; break;
                            case execute:
                                ((func_ptr)item[select].variable)();
                                break;
                            case none:
                                return;
                        }
 
А разные типы char, int итд, пока не нужно, так как эти переменные хранятся в конфигурационной EEPROM и для облегчения жизни они все одного размера. "Исполняемую" типу я захотел, так как у меня есть еще одна функция, которая вызывает разные процедуры в процессе работы. Так вот оно меня перестало удовлетворять, так как там я не могу с малой болью переставить элементы меню местами (а в этом я могу) и поэтому чтобы не делать ту же работу снова захотел расширить возможности этого меню, а то - выбросить (уф, сам не понял, что написал).

Зато хорошая идея использовать безымянный тип *void если переменная может исполнять разные роли. Опасался, что нужно будет править все места, где у меня идёт обработка, где они должны указывать на целые числа, но оказалось, что там я всё делал через указатель int *str_ptr, а присваивание этому указателю этого *void даже предупреждения не выдало и не нужно было делать cast.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

я в случаях, когда надо одним указателем работать с разными типами данных, использую внутри структур юнионы анонимные (а без структур - обычные), GCC позволяет так делать:

Код: Выделить всё

typedef union{
   void(*function)(int*);
   uint32_t *ptr32;
   char *str;
} my_ptr_t;

my_ptr_t var;
в параметрах функций или где надо, работаю с переменной этого типа, просто разыменовывая её так, как надо по символьным именам, без принудительного typecast-а, например var.str - это будет строка, *var.ptr32 - это будет 32-битное число, а вызвать функцию можно так var.function(12)... очень удобно, и при автоподстановке не ошибешься. все остальное делает компилятор.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

Ну да. Обычно так и делается - структура, в которой два поля - 1) enum типа и 2) union разных типов.

Оно и при сериализации можно использовать, когда нужно разнородные данные уметь отправлять по какой-нибудь шине в другой МК, например.
Аватара пользователя
uldemir
Друг Кота
Сообщения: 7359
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Re: Вопросы по С/С++ (СИ)

Сообщение uldemir »

Пока работаю с Keil, и что-то не получается:

Код: Выделить всё

typedef union{
   void(*function)(void);
   int *ptr32;
} my_ptr_t;

typedef struct {
    unsigned char todisplay[16];
                    my_ptr_t variable;
         datatype_t datatype;
} menuitem_t;
const menuitem_t menu_item[] = { 
        {"PathLength xxxxx", &data.pathlength,            decimal},
        {"Loop Num   xxxxx", &data.loop,                        decimal},
... 
    {"Free Run        ", FreeRun,                execute},
 
выдал ошибки. Похоже, оно ожидало только первый формат void(*function)(void). На строчку {"Free Run ", FreeRun, execute} возражений не было.

Код: Выделить всё

main.c(146): error:  #144: a value of type "int *" cannot be used to initialize an entity of type "void (*)(void)"
                {"PathLength xxxxx", &data.pathlength,                  decimal},
main.c(147): error:  #144: a value of type "int *" cannot be used to initialize an entity of type "void (*)(void)"
                {"Loop Num   xxxxx", &data.loop,                                                decimal},
И вот сейчас не могу вспомнить кто, но кто-то очень жаловался на анонимные юнионы и поэтому я их стал редко использовать - стал кастить указателями. Эти 32-битные данные в EEPROM пишу, ведь, как байты...

Код: Выделить всё

	pData = (unsigned char*)(&data);
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Аватара пользователя
da-nie
Говорящий с текстолитом
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение da-nie »

А что у вас за контроллер?
И день и ночь в пути...
Мои программки: https://github.com/da-nie
Мои публикации: https://habr.com/ru/users/da-nie/posts/
Мои видео: https://www.youtube.com/channel/UCUroi3 ... 52g/videos
Аватара пользователя
WiseLord
Друг Кота
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение WiseLord »

uldemir, по коду непонятно.

Во-первых, отступы так пляшут, что непонятно, как Вы с этим разбираетесь.

Во-вторых, из этого кусочка неизвестно, что такое data.pathlength, data.loop
Аватара пользователя
uldemir
Друг Кота
Сообщения: 7359
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Re: Вопросы по С/С++ (СИ)

Сообщение uldemir »

Эээээ... В данный момент MSP432P401R, но этот же код применяется и в STM32f051 и CY8C5268. Первых двух пользую в Keil, а последнего в PSoC Creator. Первого я раньше пользовал в Code Compose Studio, но быстро с него слез, так как на нетбук я не могу поставить 9-ю версию (нетбук 32-битный), а стационарный комп нельзя загнать в гибернацию, если остался студио запущен - в течение минуты комп включается снова сам.

WiseLord, data.xxxxxxx - это как раз и есть набор переменных типа int (32-битные). А то что "пляшут", так исходники правятся постоянно в разных средах, кто-то ставит табуляцию, кто-то ставит пробелы вместо них... Ну а потом в этом редакторе еще пытаюсь выравнять и получается еще хуже. извините.
Спойлер

Код: Выделить всё

typedef struct {
    int threshold;
    int maxspeed;
    int turnspeed;
    int minspeed;
    int acceleration;
    int k_error;
    int k_diff;
    int div_sigma;
    int on_way;
    int timetorun;
...итд
} eedata_t ;

extern eedata_t data;
тфу, последовательность то не совпадает. Ну это и было целью отвязать группировку параметров на экране от расположения в конфигурационном ПЗУ, потому как если я ввёл еще один параметр для работы мотора - пусть на экране он будет у моторов, но в ПЗУ просто на следующем свободном месте, чтобы остальные конфигурационные параметры не потерялись. Так что loop и pathlength они тоже есть в этом списке.
Но это ничего, Ваш вариант с void* меня вполне устраивает. Уже переправил код, всё работает. Осталось убрать неиспользуемый больше код и всё будет здорово!
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

uldemir писал(а):что-то не получается:
очень советую использовать инициализацию с структур с указанием полей, тогда проблем не должно быть:

Код: Выделить всё

typedef typedef struct {
   unsigned char   todisplay[16];
   union{ // для структур лучше использоать анонимный юнион, а не отдельный тип - я ж писал об этом
      void(*function)(void);
      int *ptr;
   };      
   datatype_t datatype;
} menuitem_t;

const menuitem_t menu_item[] = { 
   {.todisplay = "PathLength xxxxx", .ptr = &data.pathlength,  .datatype = decimal},
   {.todisplay = "Loop Num   xxxxx", .ptr = &data.loop,  .datatype = decimal},
... 
   {.todisplay = "Free Run        ", .function = FreeRun, .datatype = execute}
};
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Аватара пользователя
uldemir
Друг Кота
Сообщения: 7359
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Re: Вопросы по С/С++ (СИ)

Сообщение uldemir »

Keil не хочет анонимные юнионы:

Код: Выделить всё

configure.h(12): error:  #3092: anonymous unions are only supported in --gnu mode, or when enabled with #pragma anon_unions
А я не знаю, хочу ли я их включать...
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Аватара пользователя
ARV
Ум, честь и совесть. И скромность.
Сообщения: 18544
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск
Контактная информация:

Re: Вопросы по С/С++ (СИ)

Сообщение ARV »

uldemir писал(а):Keil не хочет анонимные юнионы:
а вы заставьте! включите ему режим С99... я по кейлу не спец, но не поверю, что он не поддерживает!

Добавлено after 1 minute 4 seconds:
блин, только сейчас усмотрел: вам же компилятор сам написал, что надо сделать!
uldemir писал(а):anonymous unions are only supported in --gnu mode, or when enabled with #pragma anon_unions
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Ответить

Вернуться в «Разные вопросы по МК»