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

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

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

Сообщение 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
Контактная информация:
Реклама
Друг Кота
Аватара пользователя
Сообщения: 7383
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Сообщение 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
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18793
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение 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)... очень удобно, и при автоподстановке не ошибешься. все остальное делает компилятор.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

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

Сообщение WiseLord »

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

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

Сообщение 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);
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Реклама
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1590
Зарегистрирован: Вс июн 24, 2012 16:07:00
Откуда: Лен.Обл.

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

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

Сообщение WiseLord »

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

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

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

Сообщение 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
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18793
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение 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}
};
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

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

Сообщение uldemir »

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

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

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

Сообщение 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
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Грызет канифоль
Аватара пользователя
Сообщения: 275
Зарегистрирован: Вс окт 20, 2019 13:03:56

Сообщение Shuspano »

Добрый день.
Столкнулся с такой ошибкой в подпрограмме setup():

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

D:\avr\hc164.c:17:2: error: stray '\302' in program
  PORT┬ |=  (1 << PB0);
  ^
сама подпрограмма:

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

void setup(void)
	{
	DDRB  |=  (1 << PB0)|(1 << PB1)|(1 << PB2);
	DDRD  &= ~(1 << PD7);
	DDRD  |=  (1 << PD6);
	PORTВ |=  (1 << PB0); 
	}

Ощущается состояние обутости в лыжи. Ну вот что тут может быть не так?
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

*фэйспалм.джпг*

Вам же в ошибке явно написано в чем проблема. Не PORTB у вас там, а PORTВ написано. Не видите разницы? А она есть. Не надо кириллицей пытаться замещать латинские буквы с таким же написанием.
Грызет канифоль
Аватара пользователя
Сообщения: 275
Зарегистрирован: Вс окт 20, 2019 13:03:56

Сообщение Shuspano »

Упс...Извините. Ну я это не специально.
Часто avr-gcc указывает на ошибки там где их нету, или их описание настолько лапидарно, что в целом, ни о чем. Уже привык.
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

Ну видно же, что вместо PORTB в выводе комилятора уже написано "PORT┬". И выше текст о недопустимом символе. Это и должно было на мысль натолкнуть.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18793
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Shuspano писал(а):Часто avr-gcc указывает на ошибки там где их нету
с роду такого не было! примеры в студию
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Грызет канифоль
Аватара пользователя
Сообщения: 275
Зарегистрирован: Вс окт 20, 2019 13:03:56

Сообщение Shuspano »

[uquote="ARV",url="/forum/viewtopic.php?p=3838320#p3838320"]
Shuspano писал(а):Часто avr-gcc указывает на ошибки там где их нету
с роду такого не было! примеры в студию[/uquote]

Ну вот например:

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

D:\comp\avr8-gnu-toolchain\bin>avr-gcc -Os -mmcu=attiny13a -o d:\avr\hc164-13a.e
lf d:\avr\hc164.c
d:\avr\hc164.c: In function 'hc595latch':
d:\avr\hc164.c:99:2: error: expected declaration or statement at end of input
  }
  ^
Строка 99 = закрывающая скобка подпрограммы main()

весь код:
Спойлер

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

#define F_CPU 8000000UL

#define	sclock	PB2
#define sdata	PB0
#define latch	PB4
#define rdata	PB3

#include <avr/io.h>
#include <util/delay.h>

void setup(void)
	{
	DDRB  |=  (1 << sdata)|(1 << sclock)|(1 << latch);
	DDRB  &= ~(1 << rdata);
	}

void sh_pulse(void)
	{
	PORTB |=  (1 << sclock);
	PORTB &= ~(1 << sclock);
	}

void hc165latch(void)
	{
	PORTB &= ~(1 << latch);
	PORTB |=  (1 << latch);
	}
	
void hc595latch(void)
	{
	PORTB |=  (1 << latch);
	PORTB &= ~(1 << latch);

void hc595send(unsigned char hc595data)
	{
	PORTB |= (1 << latch);
	
	int i; 
	for (i=0; i<8; i++)
		{
		if (hc595data & 0x80)
			{
			PORTB |= (1 << sdata);
			}
		else
			{
			PORTB &= ~(1 << sdata);
			}
		hc595data = hc595data << 1;
		sh_pulse();
		}
	hc595latch();
	}

unsigned char hc165read()
	{
	PORTB &= ~(1 << latch);
	
	unsigned char hc165data;
	int y;
	hc165latch();
	for (y=0; y<8; y++)
		{
		hc165data = hc165data << 1;
		if (PINB & (1 << rdata))
			{
			hc165data |=  (1 << 0);
			}
		else
			{
			hc165data &= ~(1 << 0);
			}
		sh_pulse();
		}
	return(hc165data);
	}
		
/*
void ledflash(void)
	{
	PORTD |=  (1 << ledpin);
	_delay_ms (5);
	PORTD &= ~(1 << ledpin);
	_delay_ms (5);
	}
*/

void main(void)
	{
	setup();
	while(1)
		{
		unsigned char j;
		j = ~hc165read();
		hc595send(j);
		ledflash();
		_delay_ms(50);
		}
	}
 
если это не компилятор выделывается, то что это?
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

Shuspano, ошибка состоит из 2х строк, а не одной. Над сторокой со строкой ошибки, есть еще одна строка =/
d:\avr\hc164.c: In function 'hc595latch':
Сразу должно смутить, что функция hc595latch у нас идет до 99ой строки. Смотрим - и у функции пропущена закрывающая }. И конечно же компилятор считает, что эта функция продолжается до конца файла и резко обрывается, не закрываясь должным образом. Потому что компилятор прежде чем разбирать саму функцию, ищет её начало и конец по { }. И не находит в вашем случае.
На самом деле ошибка вполне очевидная, если понимать это.
Модератор
Аватара пользователя
Сообщения: 4618
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

Мало того, ещё и ledflash закоменчен. Хотя пытаются его вызвать :facepalm:

Добавлено after 1 minute 30 seconds:
[uquote="Shuspano",url="/forum/viewtopic.php?p=3839044#p3839044"]если это не компилятор выделывается, то что это?[/uquote]Руки, сударь, руки ...

PS: Всегда удивляли вот такие компиляторвиноват'оры. Конечно, а ктож ещё, не они же сами :)))
Ответить

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