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

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Друг Кота
Аватара пользователя
Сообщения: 6296
Зарегистрирован: Пн ноя 22, 2010 00:57:15
Откуда: Ukraine

Сообщение FreshMan »

вопрос относительно построения программы по модульному принципу
допустим в моем проэкте есть два модуля
main.c
module_1.c

по общепринятым правилам в main.c я должен прописать хидер #include "module_1.h" в котором я должен обозначить прототипы ф-ций
1)зачем в данном случае вообще нужен хидер ? ведь все файлы которые есть в проэкте с расширением с при компиляции все-равно сливаются воедино
2) почему бы тогда в хидере не писать сразу все ф-ции целиком ?
Tell Me The Truth
Реклама
Опытный кот
Аватара пользователя
Сообщения: 838
Зарегистрирован: Вт апр 12, 2011 18:38:19
Откуда: с Земли

Сообщение coredumped »

FreshMan писал(а):
по общепринятым правилам в main.c я должен прописать хидер #include "module_1.h" в котором я должен обозначить прототипы ф-ций
1)зачем в данном случае вообще нужен хидер ? ведь все файлы которые есть в проэкте с расширением с при компиляции все-равно сливаются воедино
2) почему бы тогда в хидере не писать сразу все ф-ции целиком ?
#include "module_1.h" выполняется препроцессором и вызывает вставку всего содержимого файла "module_1.h" в компилируемый файл. Если Вы опишите в "module_1.h" функции полностью, а не только прототипы, то файлы скомпилятся, однако при линковке Вы получите сообщение об ошибке (что-то типа "функция с именем бла-бла объявлена несколько раз"). Это, если хидер включен в несколько модулей программы.
Поэтому, делается так: пишем функции в отдельном модуле - файле xxx.c, затем создаем хидер (xxx.h), содержащий прототипы функций, которые мы хотим использовать в других модулях, а в самих модулях делаем включение #include "xxx.h".
Включение нужно для того, чтоб компилятор понял какие именно параметры будут в функции, которая позднее будет подлинкована из других модулей. Можно вместо хидера писать в каждом модуле описание прототипа функции, например extern int my_blackbox(int a);(extern можно не писать для большинства компиляторов).
Еще оди совет: в хидерах используйте условное объявление типа #ifndef _MODULE_H_ #define _MODULE_H_ ... содержимое хидера ... #endif
Пример:

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

#ifndef __FPGA_CONF_H
#define __FPGA_CONF_H

#include "stm32f4xx.h"

#define FPGA_INIT_CYCLE		50		/* extra DCLK cycles while initialization is in progress */
#define FPGA_RECONF_COUNT_MAX	5		/* #auto-reconfiguration when error found */
  
uint8_t fpga_load(void);

#endif  /* __FPGA_CONF_H */
Это позволит избежать ошибок компиляции, если хидер включен в цепочку несколько раз. Такое бывает, если хидер включен в другие хидера... Короче используйте подобный скелет во всех хидерах, это сократит количество предупреждений и ошибок компиляции.
Все будет только лучше, в крайнем случае - хуже.
Реклама
Друг Кота
Аватара пользователя
Сообщения: 6296
Зарегистрирован: Пн ноя 22, 2010 00:57:15
Откуда: Ukraine

Сообщение FreshMan »

coredumped писал(а):Это, если хидер включен в несколько модулей программы.
а если он включен только в один модуль ?
если мой проэкт имеет только один модуль, ну окромя главного(main), то тогда можна прямо в хидере описывать полностью ф-ции ?
Tell Me The Truth
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

то тогда можна прямо в хидере описывать полностью ф-ции ?
Можно. Но не стоит так делать - кто знает, что Вы захотите с этими файлами сделать потом... Вообще обычно модули пишут в частности и для того, чтобы использовать код повторно.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
lix
Опытный кот
Сообщения: 703
Зарегистрирован: Вс янв 17, 2010 15:32:19
Откуда: Курган

Сообщение lix »

то тогда можна прямо в хидере описывать полностью ф-ции ?
можно, только если потом включить этот хидер более чем в один с-файл, то получите ошибку о множественом определении функций.
Реклама
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2482
Зарегистрирован: Пт авг 27, 2010 05:57:06
Откуда: Тюмень

Сообщение vitalik_1984 »

coredumped писал(а):Еще оди совет: в хидерах используйте условное объявление типа #ifndef _MODULE_H_ #define _MODULE_H_ ... содержимое хидера ... #endif
Это все правильно только чувак задал вопрос зачем они вообще нужны эти модули.
Вот ответ
YS писал(а):Вообще обычно модули пишут в частности и для того, чтобы использовать код повторно.
Так сказать для уменьшения времени разработки и тестирования программ. То есть если какая то полезная функция будет написана внутри основного файла будет очень трудно вынести данный код из общей массы. А так легко использовать модуль, который создан для выполнения одной конкретной задачи.
Так же создание отдельных файлов позволяет компилировать их отдельно, что так же позволяет сократить время разработки больших проектов. Не прибегая к полной компиляции.
Это было по первому вопросу вот еще в Вики статья
А по второму вопросу немного другая тема
Вот статья
Контактная информация:
Реклама
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 27
Зарегистрирован: Чт мар 21, 2013 16:22:09

Сообщение Alkarax »

Здравствуйте коты, разбираюсь с подключением AVR по юсб, нашел отличный проект, но теперь не могу разобраться с программой на стороне компа, в проекте есть Dll библиотека и пользовательская программа в качестве примера, но они на Delphi, а я пишу на с++ и дельфи вообще не знаю. В проекте упоминается, что данную Dll можно использовать и для с++, подскажите пожалуйста как это делается.
Вот ссылка проекта http://www.gaw.ru/html.cgi/txt/app/micr ... AVR309.htm, там же в конце все файлы.
Мудрый кот
Аватара пользователя
Сообщения: 1810
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Сообщение Kavka »

Если смотрите на программную реализацию USB на AVR-ках, то лучше используйте вот эту реализацию.
http://www.obdev.at/products/vusb/index.html
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 27
Зарегистрирован: Чт мар 21, 2013 16:22:09

Сообщение Alkarax »

Спасибо, но тот, про который я говорю считаю лучшим, потому что там реализована сразу куча функций, не переделывая прошивки я могу делать на одном микроконтроллере конечное устройство и, самый главный плюс, здесь есть примеры всех этапов программирования от железячки до конечного пользователя. Просто я сейчас делаю курсовую, мне нужно разработать драйвер, драйвер я худо-бедно разобрал полностью, а вот dllку к нему освоить не получается никак, повторюсь в дельфи я полный 0.
Сверлит текстолит когтями
Аватара пользователя
Сообщения: 1262
Зарегистрирован: Пн дек 08, 2008 10:58:48
Откуда: Винница

Сообщение urry »

http://forum.sources.ru/index.php?showtopic=248068
здесь находится h файл для загрузки этой длл.
Но на месте препода я бы это не принял - тема умерла лет так 10 назад. Ну скажем, утратила актуальность :)
Когда мега работает с юсб, она больше практически ни на что не отвлекается - да и делает это достаточно криво. Сейчас полно дешевых мк с аппаратным блоком юсб.
Контактная информация:
Первый раз сказал Мяу!
Аватара пользователя
Сообщения: 27
Зарегистрирован: Чт мар 21, 2013 16:22:09

Сообщение Alkarax »

Большое спасибо! Я с вами не спорю, я все собираюсь начать осваивать stm32,там и юсб и сами они посовременнее, но постоянно что-то отвлекает. На счет принял бы или нет препод, то почему нет, ведь задача стоит научиться писать драйверы, а как работает все что выше или ниже его - без разницы, это уже просто моя личная любознательность. Просто Вы не представляете в каком отсталом месте я учусь и изначально мне давали задание написать драйвер консоли для дос на ассемблере, я подумал что если уж тратить время, то на что-то хоть немного полезное и интересное. Если Вас не затруднит, можно примерчик вызова любой функции из этой библиотеки, а то везде натыкаюсь на примеры с использованием lib? И еще вопрос: по ссылке что вы дали речь идет о старой и новой версии данной dll, файл .h там как я понял к старой, а dll у меня новая, нужно мне изменять файл .h или так работать тоже будет? Или я вообще что-то не так понял?
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Здравствуйте, почему у меня не получается сделать обращение через точку к структуре

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

typedef struct List_IP_PORT1 {
  unsigned char   n;
  unsigned char   IP[2][4];
  unsigned int   port[2];
} List_IP_PORT;
Через указатель работает всё

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

List=(List_IP_PORT *)srt_buf;
   List->n=number;
   List->IP[0][0]=ip1[0];
   List->IP[0][1]=ip1[1];
   List->IP[0][2]=ip1[2];
   List->IP[0][3]=ip1[3];

   List->IP[1][0]=ip2[0];
   List->IP[1][1]=ip2[1];
   List->IP[1][2]=ip2[2];
   List->IP[1][3]=ip2[3];

   List->port[0]=port1;
   List->port[1]=port2;
Делаю вот так вот

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

List_IP_PORT.n=24;
Rомпилятор(IAR) ругается
Error[Pe040]: expected an identifier C:\STM32\W5100 v12(trap list)\main.c 114
Error[Pe144]: a value of type "int" cannot be used to initialize an entity of type "List_IP_PORT" C:\STM32\W5100 v12(trap list)\main.c 114

Пытаюсь разобраться в чём отличия обращения к элементам структуры через точку или стрелочку. Пока только одна мысль что через стрелочку можно структуру наложить на массив а через точку нет.
Вымогатель припоя
Сообщения: 630
Зарегистрирован: Пн июн 14, 2010 13:07:29
Откуда: Жуковский

Сообщение a_skr »

List_IP_PORT - это тип. Объявите переменную вашего типа и обращайтесь через точку:
List_IP_PORT x;
x.n = 5;
Стрелочкой :) работают с указателями.
Встал на лапы
Сообщения: 145
Зарегистрирован: Ср фев 01, 2012 10:55:53

Сообщение BorisSPB »

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

List=(List_IP_PORT *)srt_buf;
С приведением типов указателей надо быть осторожным. Элементы в структуре могут быть расположены с выравниванием и например List_IP_PORT.n может занимать не один байт, как задумывалось, а два. Поэтому если идет разбор потока байт, структуру List_IP_PORT следует определить с атрибутом __packed или подобным. А еще могут быть проблемы с выравниванием доступа к памяти процессора, об этом надо тоже не забывать.
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

Делаю вот так вот
В Вашем случае List_IP_PORT это тип, определенный через typedef. Соответственно, ему ничего нельзя присвоить. :) На доступном примере: это все равно, что написать int=2.

Как сказали выше, надо объявить переменную этого типа и использовать ее. :)

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

List_IP_PORT my_list;

...

my_list.n=24;

...
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Контактная информация:
isx
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Сообщение isx »

Вечер добрый!
Помогите пожалуйста справиться с 74HC595. Написал код для проверки, но он не пашет. Подскажите пожалуйста, где ошибка?

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



 if (b1 == 0) { 
 PORTB.2 = 0x00;  //ST
 PORTB.0 = 0x00;  //SH
 PORTB.3 = 0x00;  //MR
 delay_us(2);
 PORTB.3 = 0x01;   //MR
 for ( x1=0;x1<8;x1++) { 
PORTB.1 = AA1[x1];     // char AA1[8] = {0,0,0,1,0,0,0,0};
PORTB.0 = 0x01;   //SH
delay_us(2);
PORTB.0 = 0x00;  //SH   
}
b1 = 1; 
PORTB.2 = 0x01; //ST
delay_us(2);
PORTB.2 = 0x00; //ST



} 
  
 else {PORTB.3 = 0x00;}   //MR    
Пардон :)
Код рабочий, я просто не соединил в протеусе пин OE на землю. Щас наткнулся только на статью, где такое действие описано...
YS
Друг Кота
Аватара пользователя
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05

Сообщение YS »

Скажу честно - мне лень анализировать, где конкретно ошибка. :) Давайте я покажу, как это работает у меня...
Спойлер

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

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

#define HC_PORT		PORTD
#define HC_DDR		DDRD
#define HC_ST		(1<<PD6)
#define HC_SH		(1<<PD7)
#define HC_DS		(1<<PD5)

void HC_InitLines(void)
{
  HC_DDR|=HC_DS | HC_ST | HC_SH;
  HC_PORT&=~(HC_DS | HC_ST | HC_SH);
}

void HC_ShiftByte(uint8_t b)
{
  uint8_t msk;

  HC_PORT&=~HC_ST;

  for (msk=0x80; msk; msk=msk >> 1)
  {
    HC_PORT&=~HC_SH;

    if (b & msk)
	{
	  HC_PORT|=HC_DS;
	}
	else
	{
	  HC_PORT&=~HC_DS;
	}

	HC_PORT|=HC_SH;
  }

  HC_PORT|=HC_ST;
}

void main(void)
{
  HC_InitLines();

  while (1)
  {
    HC_ShiftByte(0x55);
	_delay_ms(500);
	HC_ShiftByte(0xAA);
	_delay_ms(500);
  }
}
Щас наткнулся только на статью, где такое действие описано...
Вообще, начинать изучение любой микросхемы принято с официальной документации. :wink:
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Контактная информация:
isx
Поставщик валерьянки для Кота
Аватара пользователя
Сообщения: 2316
Зарегистрирован: Вс июн 26, 2011 20:03:21

Сообщение isx »

YS писал(а):
Вообще, начинать изучение любой микросхемы принято с официальной документации. :wink:
Был бы мой английский столь совершенен, чтоб разобрать без бутылки что там написано... :))
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение pokk »

Благодарю за помощь теперь стало понятнее.
BorisSPB писал(а):С приведением типов указателей надо быть осторожным
В данном примере это не сильно важно но вот в другой структуре это критично. Но пока всё работает стабильно если что отвалится буду знать куда копать.(Я так понял что отвалится она может при смене компилятора или если в настройках выравнивания структуры похимичить ?)

И ещё не большой вопросик появился если надо передать в функцию много параметров штук 10 как это сделать правильно ?
Причём из этих 10 штуки 2-3 это массивы. Если всё в лоб то она большая сильно становится.
По пробовал эти все параметры запихать в структуру и в функцию только структуру передавать. Но всё равно перед функцией
все эти данные объявить. Хотя мне так больше нравится.

А как быть с таким вот случаем

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

typedef struct Setting {
  u8_t community[20];
  u8_t n;
} Setting;
если содержимое массива community меньше 20 к примеру 10 занимается остальное нули. как сделать что бы вместо нулей была переменная n ? думал сделать вот такое но адрес community почему-то 0.

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

typedef struct Setting {
  u8_t *community;
  u8_t n;
} Setting;
Опытный кот
Аватара пользователя
Сообщения: 838
Зарегистрирован: Вт апр 12, 2011 18:38:19
Откуда: с Земли

Сообщение coredumped »

Если размер массива меняется, то логично использовать указатель, как Вы написали, однако указателю нужно присвоить значение - адрес массива. Те сначала нужно выделить память под массив, а потом присвоить адрес этой памяти массиву. Механизмы выделения-освобождения памяти отличаются от операционной системы, под которую пишется программа. Вот пример под Linux с Вашей структурой

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

typedef struct Setting {
  u8_t *community;
  u8_t n;
} Setting;

Settings.community = malloc(100); // Выделяем 100 байт
// ...........
free(Settings.community); // Освобождаем ранее выделенную память

Таким образом мы имеем дело с динамически выделяемой памятью или "динамической памятью" (еще используется термин "куча").
Для МК тоже есть реализации упрощенного управления динамической памятью, однако в отличии от "взрослых" ОС память может выделяться из заранее отведенной области и только непрерывным блоком. Обсуждение механизмов управления динамической памятью заслуживает целой книги.
Можете погуглить словам malloc, heap.
PS: если Вы имеете дело с маленьким МК и памяти хватает, проще выделить статический массив с запасом, чем возиться с перераспределением памяти. Тут делема: производительность - расход памяти. Я советую использовать танцы с динамическим распределением, если памяти не хватает (в случае МК, естественно). Есть много методов оптимизации использования памяти, но все они приводят к снижению скорости выполнения программы.
Все будет только лучше, в крайнем случае - хуже.
Ответить

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