|
Закольцевать данные, программа на Си |
|
|
|
Jun 3 2014, 05:59
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 13-09-12
Пользователь №: 73 530

|
Вместе с указателем на данные передавать указатель на начало и конец массива?
|
|
|
|
|
Jun 3 2014, 06:02
|

Профессионал
    
Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409

|
Цитата(Dubov @ Jun 3 2014, 12:19)  Имеется буфер длины N имеется подпрограмма, принимающая на вход указатель на блок данных длины N. Буфер заполняется циклически (по заполнении буфера, новый отсчёт поступает в начало буфера). с каждым новым вызовом подпрограммы, получаемый указатель увеличивается на единицу. Как закольцевать адресацию массива? Может быть Вам стоит поступить немного иначе - организовать 2 функции putArray(data) и getarray() putArray(data) закидывает данные в буффер, контролируя при этом переход через границу буффера и смещая позицию head (позицию куда необходимо закидывать следующие данные) Код void putarray(short data) { buff[head] = data; head++; if(head >= BUFF_SIZE) head = 0; //переход через границу буффера } Функция getArray() возвращает или-1 если нет данных, или данные Код signed int getArray(void) { signed int res = -1; if(head == tail) return res; //нет данных - возвращаем -1 res = buff[tail]; tail++; if(tail >= BUFF_SIZE) tail = 0; return res; //возвращаем данные
} Эти 2 процедуры позволяют организовать FIFO данных без проверки переполнения буффера. Если Вам критично отслеживать переполнение, то всегда можно ввести переменную status, которой можно присваивать статусы empty/not_empty/full Также довольно легко вместо данных, возвращать указатели на данные.
|
|
|
|
|
Jun 3 2014, 06:38
|
Местный
  
Группа: Участник
Сообщений: 408
Регистрация: 28-05-12
Пользователь №: 72 052

|
Цитата(menzoda @ Jun 3 2014, 14:09)  Вместе с указателем на данные передавать указатель на начало и конец массива? допустим, функция кроме указателя на начало данных получила указатель на начало и конец массива. Как это обработать на Си, чтобы за концом массива, брались данные из начала? Пока что я думаю завести переменную счётчик, чтобы знать положение PTR в массиве, когда вызывается функция обработки, копировать данные в другой массив, той же длины с учётом счётчика. Как то так: j = count; for(i = 0; i <= N-1; i++) { array_dest[i] = array_src[j]; j++; if(j == N) j = 0; } где count = это положение самого "свежего отсчёта" в массиве array_src. таким образом, мы получим в массиве array_dest всегда данные начиная с самого свежего элемента исходного массива. Такой подход самый тупой и, что называется, в лоб. мне думается, что он будет самым затратным из возможных, и для реалтаймовых задач нерациональным. Цитата(mempfis_ @ Jun 3 2014, 14:12)  Функция getArray() возвращает или-1 если нет данных, или данные Код signed int getArray(void) { signed int res = -1; if(head == tail) return res; //нет данных - возвращаем -1 res = buff[tail]; tail++; if(tail >= BUFF_SIZE) tail = 0; return res; //возвращаем данные
} Эти 2 процедуры позволяют организовать FIFO данных без проверки переполнения буффера. Если Вам критично отслеживать переполнение, то всегда можно ввести переменную status, которой можно присваивать статусы empty/not_empty/full Также довольно легко вместо данных, возвращать указатели на данные. не понимаю, ну получил я указатель на данные в буфере. Функция обработки берёт по указателю N байт (по сути весь массив с началом в указателе) и если указатель пришёлся на конец буфера, то функция возьмёт данные где-то пределами массива. В идеале мне нужна циклическая адресация, чтобы за концом массива шло начало в адресном пространстве.
Сообщение отредактировал Dubov - Jun 3 2014, 07:23
|
|
|
|
|
Jun 3 2014, 07:30
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(mempfis_ @ Jun 3 2014, 13:12)  Функция getArray() возвращает или-1 если нет данных, или данные Код signed int getArray(void) { signed int res = -1; if(head == tail) return res; //нет данных - возвращаем -1 res = buff[tail]; tail++; if(tail >= BUFF_SIZE) tail = 0; return res; //возвращаем данные } Только в этой функции, я думаю , не увеличение tail а набоборот: Код signed int getArray(void) { signed int res = -1; if(head == 0) return res; //нет данных - возвращаем -1 res = buff[tail]; tail--; return res; //возвращаем данные }
|
|
|
|
|
Jun 3 2014, 07:43
|
Участник

Группа: Участник
Сообщений: 66
Регистрация: 5-05-14
Из: Минск
Пользователь №: 81 582

|
Можно сделать указатель типом BYTE. Если размер массива 256 байт, то после значения указателя 255 автоматически следующим будет 0.
|
|
|
|
|
Jun 3 2014, 07:43
|
Гуру
     
Группа: Свой
Сообщений: 2 563
Регистрация: 8-04-05
Из: Nsk
Пользователь №: 3 954

|
Цитата(Dubov @ Jun 3 2014, 17:57)  прошу прощения, можно по-подробнее об этом методе. А лучше ссылку на код (совсем наглость с моей стороны)  data[i & (size-1)] = 0; size дожен быть степенью двойки. при занулении старших разрядов автоматически получается закольцовывание массива. но ничем это не лучше дополнительных проверок на выходы за границы массива. Код void func(double * data, int size, int i0, int num){ while (num--){ while (i0 >= size) i0 -= size; process(data[i0++]); } } num может быть даже в несколько раз больше size, при этом оно пройдётся по массиву несколько раз.
|
|
|
|
|
Jun 3 2014, 07:50
|

Профессионал
    
Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143

|
Цитата(Dubov @ Jun 3 2014, 14:57)  прошу прощения, можно по-подробнее об этом методе. А лучше ссылку на код (совсем наглость с моей стороны)  к примеру ваш буфер размещен по адресу #define BUFF_START 0x1000 и занимает #define BUFF_SIZE 512 void buff_add( u8* ptr ) { *ptr++ = get_data(); ptr = (u8*) ( (int)ptr & ( BUFF_SIZE - 1 ) + BUFF_START ); // получится типо ptr = (u8*) ( (int)ptr & 0x1FF + BUFF_START ); } p.s. на скорую руку набросал.
--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
|
|
|
|
|
Jun 3 2014, 08:13
|

Профессионал
    
Группа: Свой
Сообщений: 1 001
Регистрация: 27-06-06
Пользователь №: 18 409

|
Цитата(MaxiMuz @ Jun 3 2014, 14:40)  Только в этой функции, я думаю , не увеличение tail а набоборот: Код signed int getArray(void) { signed int res = -1; if(head == 0) return res; //нет данных - возвращаем -1 res = buff[tail]; tail++; return res; //возвращаем данные } Исходный код правильный - это кольцевой буффер FIFO. По позици head ложим данные с инкрементом head. Забираем данные по позиции tail с инкрементом tail. При закидывании данных голова убегает от хвоста. При извлечении - хвост догоняет голову. Если Т.С. нужен кольцевой буффер с доступом по указателю, то megajohn уже подсказал решение. Позволю себе также пояснить то, что предложил megajohnПредположим у Вас есть буффер char-элементов buff расположенный по адресу 0x1000 и размер BUFF_SIZE = 256 байт Тогда Ваш буффер будет занимать диапазон адресов 0xFF1000 - 0x001000 Маска для этого диапазона адресов ADDR_MSK = 0xFF<<12 Теперь мы хотим считать с любой позиции буффера через указатель 256 байт, но так, чтобы при достижении границы буффера адрес автоматически перешёл в начало Код unsigned char* pbuff = &buff[255]; for(unsigned int i=0; i<BUFF_SIZE; i++) { *((pbuff+i)&ADDR_MSK); } Сначала адрес pbuff+i = 0xff1000+0 Читаем с этого адреса значение из ячейки buff[255] Далее инкремен i и адрес становится pbuff+i=0xff1000+1=0x1001000 Но мы накладываем маску адресов 0xff<<12 и получаем адрес 0x100010000&(0xff<<12) = 0x001000; Т.е. новый адрес соответсвует ячейке buff[0]; при i == 1 адрес будет 0x1011000&(0xff<<12) = 0x001000 и так далее.
|
|
|
|
|
Jun 3 2014, 08:18
|
Участник

Группа: Участник
Сообщений: 55
Регистрация: 13-09-12
Пользователь №: 73 530

|
Цитата(Dubov @ Jun 3 2014, 14:48)  допустим, функция кроме указателя на начало данных получила указатель на начало и конец массива. Как это обработать на Си, чтобы за концом массива, брались данные из начала? Так и обрабатывать. В цикле проверять не дошел ли текущий указатель до конца массива, если да, то сдвигаем его в начало массива. Код void foo(int *ptr, int count, int *start, int *end) { while(count-- > 0) { if (ptr >= end) { ptr = start; }
do_something_with(ptr); ptr++; } } Цитата(Dubov @ Jun 3 2014, 14:48)  Такой подход самый тупой и, что называется, в лоб. Мне думается, что он будет самым затратным из возможных, и для реалтаймовых задач нерациональным. Собственно других волшебных методов нет. Разве что использовать размер массива равный степени двойки. Тогда можно будет заменить условие на побитовую операцию и присвоение, но даже если это и даст выигрыш, то всего в пару тактов, что будет каплей в море.
|
|
|
|
|
Jun 5 2014, 08:15
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(mempfis_ @ Jun 3 2014, 15:23)  Тогда Ваш буффер будет занимать диапазон адресов 0xFF1000 - 0x001000 Маска для этого диапазона адресов ADDR_MSK = 0xFF<<12 Принцип понял, но непонятен механизм. Цитата(mempfis_ @ Jun 3 2014, 15:23)  Сначала адрес pbuff+i = 0xff1000+0 Читаем с этого адреса значение из ячейки buff[255] Далее инкремен i и адрес становится pbuff+i=0xff1000+1=0x1001000 Но мы накладываем маску адресов 0xff<<12 и получаем адрес 0x100010000&(0xff<<12) = 0x001000; Т.е. новый адрес соответсвует ячейке buff[0]; при i == 1 адрес будет 0x1011000&(0xff<<12) = 0x001000 и так далее. i=0 ,получаем адрес ((pbuff+i)&ADDR_MSK) = (0х00001000+0)&0x000FF000 = 0х00001000 i=1 : ((pbuff+i)&ADDR_MSK) = (0х00001000+1)&0x000FF000 = 0х00001000 тот же самый адрес, или я чего то не так понял ?
|
|
|
|
|
Jun 5 2014, 08:24
|

Профессионал
    
Группа: Свой
Сообщений: 1 080
Регистрация: 16-11-04
Из: СПб
Пользователь №: 1 143

|
Цитата(MaxiMuz @ Jun 5 2014, 16:25)  тот же самый адрес, или я чего то не так понял ? автар перепутал байт вместо "Тогда Ваш буффер будет занимать диапазон адресов 0xFF1000 - 0x001000" читать "Тогда Ваш буффер будет занимать диапазон адресов 0x0010 FF - 0x001000" и далее, сам же запутался (или HumanEndian путает с HardwareEndian ) =)
--------------------
Марс - единственная планета, полностью населенная роботами (около 7 штук).
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|