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

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

в GCC можно для отладки выводить символьное имя текущей функции: см. https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Благодарю всех за ответ и за __func__ полезная штука.
ARV писал(а):что мешает сделать ОДИН выход из функции, как того требует модульный стиль программирования?
В том что программа написана в стиле КА, вот я и хочу отслеживать КА дошёл по последнего состояния или нет. Ну и смотреть как будет осуществляться доступ из нескольких КА к одному ресурсу.

Походу изначально то что я хотел было обреченно на провал. Так как два работающих параллельных КА будут напрочь рушить мою таблицу. Выход придумал только один написать свою терминальную программку которая будут выводить так как мне надо :)
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

не вижу абсолютно никаких проблем сделать конечный автомат с одним входом и одним выходом.
изменил состояние КА - и на выход, напечатал новое состояние.

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

switch(state){
case STATE_1:
   state = STATE_5;
   break;
case STATE_2:
   state = STATE_1;
   break;
...
default:
   state = STATE_0;
}
debug_output(state);
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Добрый день, решил тут библиотеку шим для светодиодов написать.
Так как количество ШИМ изначально неизвестно, по этому решил сделать легкое создание нового шима (редактированием или добавлением define).
Так вот при создании нового ШИМ надо что бы прошла инициализации настроенных портов. В принципе через указатели можно это сделать, но не особо желаю (падает скорость работы с портом).
Пока выглядите это всё примерно так:

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

unsigned char* Mas_PORTx[MAX_PWM]={&PORTB,&PORTB,&PORTD,&PORTC};
unsigned char* Mas_DDRx[MAX_PWM]={&DDRB,&DDRB,&DDRD,&DDRC};
unsigned char  Mas_Pin[MAX_PWM]={0,1,2,3};

	for(i=0;i<MAX_PWM;i++){
		ClearBit(*Mas_PORTx[i],Mas_Pin[i]);
		SetBit(*Mas_DDRx[i],Mas_Pin[i]);
	}
Можно ли как нибудь без указателей это сделать?
Реклама
Эиком - электронные компоненты и радиодетали
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 302
Зарегистрирован: Пн янв 07, 2008 16:56:28
Откуда: Минск

Сообщение levaclaus »

в часах стоит ds1307. При старте проводится проверка
rtc_get_time(&hour,&minute,&second);
if ((hour>24)||(minute>60)||(second>60))
rtc_set_time(15,35,0);
rtc_get_date(0,&date,&month,&year);
if ((date>31)||(month>12)||(year>99))
rtc_set_date(0,2,12,15);

При выполнении этого кода ещё ни разу не был верно записан год, с чего бы это?
Реклама
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Сообщение shads »

Ех... давненько я не встречал засад в "вопросах по С" )))
Но вот вчерась уперся в феномен непонятный...

Суть в том, что есть модуль ADC который автоматом замеряет данные и пишет их в кольцевой 16 словный буфер.
Когда мне нужно, я вызываю процедурку, которая суммирует весь буфер и делит на те же 16... ну тобиш усреднение какое никакое...

Так вот прикол в том, что это при одном написании программы работает, а при другом (очевидной разницы абсолютно не наблюдаю) не работает...
Можно конечно чуть поменять конструкцию в главном файле, тогда начинает работать... но мне интересно почему именно в таком виде не работает???
Пример: Именно вот в таком виде - не работает, но если раскомментировать задержки по 1 мкс то начинает работать :shock:

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

//настройки
#define F_CPU 1000000
#include <util/delay.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
uint16_t AdcGet (void);									//объявление				
uint16_t AdcBuf [16];									//буфер накопитель


//Главный файл
int main (void)
{
	//инит ADC
	ADMUX = (0<<REFS1)| (1<<REFS0)|						//в кач-ве ИОН питание контроллера
			(0<<MUX3)| (0<<MUX2)| (0<<MUX1)| (0<<MUX0)| //канал ADC0
			(0<<ADLAR);									//выровнять вправо							
	ADCSRA = (1<<ADEN)|									//вкл АЦП
			(1<<ADFR)|									//FREE RUNNING
			(1<<ADIE)|									//прерывание по завершению преобразования
			(1<<ADPS2)| (1<<ADPS1)| (1<<ADPS0);			//предделитель
	ADCSR |= (1<<ADSC);									//запустить преобразование 

	//настройка светика
	DDRB |= (1<<6);

	//главный цикл
	sei ();										
	while(1){											

		uint16_t Adc = AdcGet();
		//_delay_us (1);
		if (Adc < 224){			

			PORTB |= (1<<6);							//если ниже порога - включаем светик
			while (1){
			
				Adc = AdcGet();
				//_delay_us (1);					
				if (Adc > 224) break;
			
			}											
			PORTB &= ~(1<<6);							//если выше порога - выключаем светик
		}			
	}
}


//функция чтения усредненных данных ADC
uint16_t AdcGet (void)								
{	
	uint16_t data = 0;	
	for (uint8_t i=0; i<16; i++)		
		data += AdcBuf [i];		
	return (data / 16);
}


//функция циклического опроса ADC
ISR (ADC_vect)
{
	sei ();
	static uint8_t counter;
	AdcBuf [counter] = ADC;
	if (++counter >= 16)	
		counter = 0;
}
Изображение



ЗЫ Добавил файлы проекта и протеуса
Вложения
111111111.png
(18.02 КБ) 601 скачивание
AVRST4_adc_test.7z
(24.78 КБ) 154 скачивания
Реклама
Модератор
Аватара пользователя
Сообщения: 4618
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

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

Первым, что бросается в глаза - отсутствие атомарного доступа к данным буфера.
Видимо, с задержками, как то подгоняется к нормальному доступу.
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Сообщение shads »

Аlex писал(а):Первым, что бросается в глаза - отсутствие атомарного доступа к данным буфера.
Видимо, с задержками, как то подгоняется к нормальному доступу.
Кажется вы правы ))))))))))))
Доработал чтение буфера с учетом атомарного доступа и все заработало :))
Спасибо за столь быстрый и столь правильный пинок :oops:

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

//функция чтения усредненных данных ADC
uint16_t AdcGet (void)								
{	
	uint16_t data = 0;	
	for (uint8_t i=0; i<16; i++){		
		cli ();
		data += AdcBuf [i];		
		sei ();	
	}
	return (data / 16);
}
Модератор
Аватара пользователя
Сообщения: 4618
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

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

Лучше применить атомарный доступ ко всему буферу целиком, а не только отдельно к байтам в слове. Т.к. любая ячейка, как и байт в слове, может измениться в любой момент в прерывании, что может привести к неправильным расчётам.
Я бы запретил прерывания на время чтения всего буфера. Ну отложится ненадолго следующее преобразование, ничего страшного не случится...

И ещё, увидел sei в прерывании. Вы уверены, что всё делаете правильно ? Я, конечно, не знаю, как там и что сохраняется в АВРах при входе в обработчик, но всё-таки советую не делать таких финтов. Можно нарваться на неприятности.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18787
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Аlex писал(а):Лучше применить атомарный доступ ко всему буферу целиком, а не только отдельно к байтам в слове. Т.к. любая ячейка, как и байт в слове, может измениться в любой момент в прерывании, что может привести к неправильным расчётам.
маловероятно (хотя и не исключено полностью), что подсчет суммы буфера потребует времени больше, чем проходит между двумя циклическими преобразованиями АЦП, ведь АЦП обычно работает на довольно низкой скорости.
то есть за время суммирования в буфере может обновиться максимум 1 ячейка, что не приведет к погрешности при принятом способе усреднения, вероятность обновления сразу двух ячеек равна нулю... ну или почти равна (я ж не знаю частоты тактирования АЦП и ядра МК)
поэтому шансов получить неверный результат немного...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Мучитель микросхем
Сообщения: 469
Зарегистрирован: Вс авг 30, 2015 03:52:59

Сообщение Pnjom-Penb »

ARV писал(а):за время суммирования в буфере может обновиться максимум 1 ячейка, что не приведет к погрешности при принятом способе усреднения, ...
Вообще-то, буфер - кольцевой, то есть, может наступить себе на радиоя*ца только в результате алгоритмической ошибки. :dont_know:
Друг Кота
Аватара пользователя
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)

Сообщение DX168B »

Добрый день. Вопрос по C++
Имею класс с реализацией двусвязного списка со своими дополнениями.
Зовется он QLIST (не путать со сторонними библиотеками, так как он целиком и полностью является моим велосипедом)
Оперирует он структурами, типа:

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

typedef struct _tag_Node
{
    long int nodeId;
    Node *next;
    Node *prev;
    void *ptr;
}Node, *pNode;
ID нужен для того, чтобы можно было идентифицировать конкретный узел.
Указатели next и prev содержат адреса следующего и предыдущего узлов соответственно.
ptr - указатель типа void. В него собственно вкладывается адрес данных, ассоциированных с этим узлом.

А это деструктор класса:

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

////////////////////////////////////////////////////////////////////////////
QLIST::~QLIST()
{                        // Удаление всех записей по уничтожению объекта (деструктор класса QLIST)
    NdPoint = NdFirst;  // Присваиваем рабочему указателю адрес первого элемента
    while(NdPoint != 0) // Цикл не выполнит ни одну итерацию, если список был пустым и прервется по удалению последнего элемента
    {
        NdFirst = NdPoint->next; // Присваиваем в качестве первого элемента следующий. 
                                //Если там NULL, то он далее скопируется NdPoint и цикл завершится.
        delete NdPoint; // Удаляем текущий
        NdPoint = NdFirst; // Присваиваем первый элемент в качестве текущего.
    }
}
Как видно, деструктор удаляет только узлы, а привязанные к узлам данные в памяти так и остаются.
Проблемы как бы нет, так как в программе я сначала перебираю весь список и удаляю привязанные данные,
за тем я удаляю сам объект класса. Но хотелось бы сделать так, чтобы деструктор класса удалял и данные.

Как я понимаю, этот механизм можно реализовать, пользуясь шаблонами классов.
Однако беда в том, что с шаблонами я совсем не дружу. Редко пишу на C++ и раньше обходился без шаблонов.
Можно ли это реализовать через шаблоны и есть какая-нибудь удобоваримая литература по шаблонам?
I am DX168B and this is my favourite forum on internet!
Контактная информация:
Модератор
Аватара пользователя
Сообщения: 4618
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

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

Шаблон тут не спасёт. Шаблон - это, как бы Вам проще объяснить, некая заготовка, не имеющая конкретного типа данных. Он (тип) определяется с объявлением объекта по этому шаблону.
Вопрос по Вашему сабжу. А что Вам мешает, удалив необходиый Node из списка, удалить данные, связанные с ним ? Ссылку то на данные имеете.
Друг Кота
Аватара пользователя
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)

Сообщение DX168B »

Alex
Просто хотел подчистить код, в котором применяется класс QLIST.

Типа, чтобы строкой

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

delete childList;
удалялись из памяти все ноды и данные с ними связанные.
Проблема в том, что под void указателем может скрываться что угодно.
А этот класс используется для формирования списков данных различного типа.
Только с условием: один список - один тип данных для всех нодов данного списка.
А на данный момент это выглядит так:

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

Widget::~Widget()
{
    Widget *pC = 0;
    childsList.pointer_begin();
    
    while(childsList.get_data_next((void**)&pC) == true)
    {
        delete pC;
    }
}
 
где childList является объектом класса QLIST.
Это деструктор класса Widget. При удалении виджета, удаляются все его дочерние виджеты.
После выхода из деструктора виджета вызывается деструктор объекта childList автоматически.
Хотя наверное это неправильно и в конструкторе класса Widget надо бы создать объект childList оператором new
и в деструкторе виджета удалить вручную childList оператором delete. Или не стоит заморачиваться?
Но по крайней мере, трассировка кучи не обнаруживает утечек памяти.
I am DX168B and this is my favourite forum on internet!
Контактная информация:
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

Плюсы-же - пусть объект сам о себе заботится:
DX168B писал(а):

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

typedef struct _tag_Node
{
    _tag_Node() : nodeId(-1), next(NULL), prev(NULL), ptr(NULL) { }
    ~_tag_Node() { delete ptr; }
    long int nodeId;
    Node *next;
    Node *prev;
    void *ptr;
} Node, *pNode;
 
Конструктор не обязателен - но инициализация лишней не бывает - а то позабытый случайно на стеке объект бабахнет на мусорном адресе при неявной деструкции.
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

DX168B писал(а):Проблема в том, что под void указателем может скрываться что угодно.
Заведите базовый объект для всех используемых типов - а потом вдарьте по ним полиморфизмом! ;)
DX168B писал(а):Только с условием: один список - один тип данных для всех нодов данного списка.
Либо взять уже готовый стандартный std::list либо изобрести такой-же my_list вручную.
DX168B писал(а):После выхода из деструктора виджета вызывается деструктор объекта childList автоматически.
Хотя наверное это неправильно и в конструкторе класса Widget надо бы создать объект childList оператором new.
Я бы сказал деструктор объекта childList вызывается неявно [как и для всех не-динамических полей класса] в ходе исполнения деструктора самого класса. И да, никакой неправильности в его не-динамичности нет - место будет выделено в области данных самого объекта класса - т.е. вместо двух объектов в куче (класс и список) вы поимеете один объект. Когда жизнь заставит разобираться с операторами присвоения объектов класса - динамические поля тоже потребуют к себе несколько завышенного внимания, чтобы впредь стараться обходиться без них. ;)
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Друг Кота
Аватара пользователя
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)

Сообщение DX168B »

Конструктор не обязателен - но инициализация лишней не бывает - а то позабытый случайно на стеке объект бабахнет на мусорном адресе при неявной деструкции.
Я в курсе. Поля структуры у меня все равно заполняются сразу же после создания.
Создаются они у меня в методах ::add(), ::insert() и в ::add_sort()
Вне класса я ничего со структурой не делаю. Все происходит внутри класса QLIST. Как рождение так и смерть этих структур.
Потому я и не заморачивался с конструкторами в структуре.

В конструкторе класса Widget, к примеру, вся инициализация есть.

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

//////////////////////////////////////////////////////////////////
// GUI wiget base class (inherited from GuiObject)

Widget::Widget()
{
    drawContext.xPos = 0;
    drawContext.yPos = 0;
    drawContext.zPos = 0;
    drawContext.xSize = 0;
    drawContext.ySize = 0;
    drawContext.zSize = 0;
    drawContext.objectID = 0;
    drawContext.extContext = 0;
    drawContext.extContextType = DRAW_EXTENDED_CONTEXT_TYPE_NONE;
    enableFlag = true;
    focusFlag = true;
    renderFunc = 0;
    eventCallBack = 0;
}
Передачу параметров в конструктор не делал. Все реализовано отдельными методами, так как
виджетами рулят внешние скрипты. Конечно, можно все инициализации структуры drawContext вынести в конструктор структуры,
что было бы правильнее, так как над ней проводятся операции и вне класса Widget. Так и сделаю. Спасибо за наводку. :)
Заведите базовый объект для всех используемых типов - а потом вдарьте по ним полиморфизмом!
Подумываю над этим. Что-то придется переделать.
Я просто поинтересовался, можно ли сделать это более изящно, чем то, что у меня сейчас есть.
Либо взять уже готовый стандартный std::list либо изобрести такой-же my_list вручную.
Ну, свой лист я создавал не просто так. Дело в том, что по этому списку производится рендеринг, по нему же идет перебор
при передачи событий объектам. Рендеринг объектов должен производиться в особом порядке из-за особенностей OpenGL.
И этот порядок динамически изменяется под действием кучи параметров.
А std::list у меня уже используется в других местах.
Я бы сказал деструктор объекта childList вызывается неявно [как и для всех не-динамических полей класса] в ходе исполнения деструктора самого класса. И да, никакой неправильности в его не-динамичности нет - место будет выделено в области данных самого объекта класса - т.е. вместо двух объектов в куче (класс и список) вы поимеете один объект. Когда жизнь заставит разобираться с операторами присвоения объектов класса - динамические поля тоже потребуют к себе несколько завышенного внимания, чтобы впредь стараться обходиться без них. ;)
Да уж стараюсь поменьше плодить динамических сущностей. Ибо это бьет как по надежности, так и по производительности.
И после дебага всегда проверяю логи по утечкам. Собственно, у меня и был вопрос по механизмам освобождения памяти.
Просто небыло понятно про неявный вызов деструктора childList. Это типа стандарт, или особенность одного компилятора?
Просто сейчас это пишется в Visual Studio 2010, потом будет переезжать на GCC, когда будет портироваться под Linux.

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

~_tag_Node() { delete ptr; } 
А корректно ли поведет себя оператор delete в этом случае?
Просто удаление объектов происходит одним способом, а удаление, допустим, строк (массивов) другим способом.
Ну, типа void может ссылаться как объект класса так и на обычную строку. А этот самопальный класс у меня используется и для списков строк, а в некоторых случаях и для отдельной строки. По символу на ноду. Просто в OpenGL рендеринг динамического текста - тот еще секас.
I am DX168B and this is my favourite forum on internet!
Контактная информация:
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

DX168B писал(а):Рендеринг объектов должен производиться в особом порядке из-за особенностей OpenGL.
И этот порядок динамически изменяется под действием кучи параметров.
Ну т.е. он ещё и сортируется время от времени? В STL, кстати, алгоритмы есть разные - в т.ч. с заданием критериев обработки. Пока непонятно в чем преимущество самопального списка. ;) Я вот вообще разленился - даже буфера через std:vector выделяю. :)
DX168B писал(а):Просто небыло понятно про неявный вызов деструктора childList. Это типа стандарт, или особенность одного компилятора?
Просто сейчас это пишется в Visual Studio 2010, потом будет переезжать на GCC, когда будет портироваться под Linux.
Вызов деструктора для не-динамических объектов - обязанность компилятора, либо по выходу из блока в котором он был объявлен, либо по уничтожению объекта-владельца как в описываемом случае.
DX168B писал(а):

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

~_tag_Node() { delete ptr; } 
А корректно ли поведет себя оператор delete в этом случае?
Просто удаление объектов происходит одним способом, а удаление, допустим, строк (массивов) другим способом.
В данном случае никакой информации об объекте нету - и даже если скомпилирует без предупреждений-ошибок - всё, скорее всего сведётся к вызову free для освобождения указуемого блока памяти. Если же указывается объект - то будет исполнен его деструктор - даже если тип этого указателя - абстрактный базовый. Для удаления массивов выделенных посредством new[] хорошо не забывать использовать delete[] - ибо деструкторы всех элементов жаждут исполнения. А для строк есть std::string.
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Друг Кота
Аватара пользователя
Сообщения: 4468
Зарегистрирован: Вс янв 24, 2010 19:19:52
Откуда: Главный Улей России (Moscow)

Сообщение DX168B »

Пока непонятно в чем преимущество самопального списка. ;)
Минимализм. Пробовал различные варианты. При большом количестве объектов жутко проседает FPS.
Это еще сильнее проявится, когда этот код заработает на Paspberry Pi.
Самопалом я добился нужного функционала за существенно меньшее количество операций.
Это просто узкое место в программе и тут производительность играет большую роль.
I am DX168B and this is my favourite forum on internet!
Контактная информация:
Мучитель микросхем
Сообщения: 469
Зарегистрирован: Вс авг 30, 2015 03:52:59

Сообщение Pnjom-Penb »

DX168B писал(а):А корректно ли поведет себя оператор delete в этом случае?
Про использование иерархии классов для хранения разных наборов данных уже говорили выше, а чтобы корректно отрабатывал delete, нужно объявить деструктор базового класса виртуальным. В этом случае деструктор базового класса автоматически вызывается после деструктора производного класса.
Ответить

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