Перейти к содержанию

Указатель На Массив Указателей


Br.Misha

Рекомендуемые сообщения

Привет!

Пишу одну програмку которая должна передавать данные по юсб.

Там есть указатель (uchar *usbMsgPtr;), чтобы отправить данные по юсб нужно установить указатель на первый элемент отправляемого массива, тоесть так:

uchar array[5];

usbMsgPtr = array;

После этого данные отправляются на комп. Для того, чтобы передавались именно те данные, которые мне нужны, я в процессе выполнения программы пстоянно копирую значения некоторых элементов в тот массив. Но проблема в том, что постоянное копирование переменных в тот массив занимает процессорное время, пусть не много, но в реале массив array содержит не 5 элементов а 120.

Я подумал, что лучше будет сделать массив указателей, которые указывают на нужные мне переменные, тоесть что то типа того:

uchar *array[5];

array[0] =& var0;

array[1] =& var1;

array[2] =& var2;

array[3] =& var3;

array[4] =& var4;

Но как теперь указать usbMsgPtr на этот массив указателей и вообще. Возможно ли это?

Я пробовал так usbMsgPtr = tx_buffer;, так usbMsgPtr = *tx_buffer; и так usbMsgPtr = &tx_buffer;, неработает.

спасибо!

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

Элементы массива можно использовать как переменные:

uchar array[];
...
#define VAR1 array[1]
...
VAR1=.... //находим VAR1
...
usbMsgPtr = array;

Тупо, зато просто и понятно.

Или:

#define VAR(X) array[X]
VAR(1)=...

Чтоб не писать кучу дефайнов...

Изменено пользователем Goodefine

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

Ссылка на комментарий
Поделиться на другие сайты

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Немного не понял вопрос. Напишу как получить значение varN через *usbMsgPtr

unsigned char var0,var1,var2,var3,var4;

unsigned char *array[5];
array[0] =& var0;
array[1] =& var1;
array[2] =& var2;
array[3] =& var3;
array[4] =& var4;

unsigned char *usbMsgPtr;
usbMsgPtr = *array;
unsigned char temp;
// получить значение var0 он же array[0]
temp = *(usbMsgPtr + 0);
// получить значение var1 он же array[1]
temp = *(usbMsgPtr + 1);

Это сообщение поставляется "как есть", без каких либо гарантий. Автор сообщения не несёт какой либо ответственности

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

Ссылка на комментарий
Поделиться на другие сайты

  • 1 месяц спустя...

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

А не наоборот "char var1=&array[1];"? Сори, но ссылки плохо знаю. Вроде ж array'и должны идти последовательно, а var0-var4 создаются (в общем случае) хз где.

В данном случае это без разницы, т.к. var0-var4 тоже идут последовательно. Уточняю отчасти для себя: "char v=&arr[1]" это значит что arr[1] определен где-то раньше а v создаем только сейчас, в то же место?

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

>>А не наоборот "char var1=&array[1];"?

Проверить сейчас негде поэтому пишу чисто теоретически.

Если переводить Вашу строку "char var1=&array[1];" на человеческий язык, Вы, написали: "присвоить значению переменный var1 адрес первого элемента массива arryy" :D C учетом того, что адрес у нас 16 битное целое, то компилятор еще произведет не явное приведение типов и в результате мы получим в var1 полную ерунду.

>>создаются (в общем случае) хз где.

Нет такого понятие как "хз". Переменные создаются в зависимости от места их определения на стеке или в "кучи"(свободная область памяти)

Изменено пользователем rtfcnf

Это сообщение поставляется "как есть", без каких либо гарантий. Автор сообщения не несёт какой либо ответственности

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

Ссылка на комментарий
Поделиться на другие сайты

присвоить значению переменный var1 адрес первого элемента массива arryy
извиняюсь если некорректно выразился. Имелось в виду, что var1 указывает на ту же область памяти что и arr[1], то есть по сути это одна переменная с двумя именами. В асме это выглядит как .equ var1=arr+1 (.equ т.к. создаются они очевидно в ОЗУ и не являются регистрами, +1 - потому что занимают 1 байт).
создаются (в общем случае) хз где
Опять непонятно выразился? Если создавать переменные var1-varN независимо, возможен вариант что они будут расположены не по порядку. Например если объявить var5 перед var1 или вставить между ними какой-нибудь temp.

Понятно что в данной программе этого не происходит, интересен больше теоретический аспект.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

Опять не корректно, если мы думаем и говорим в контексте "СИ" (я уважаю Ваши познания в асме, сам начинал с него) но:

>>Имелось в виду, что var1 указывает на ту же область памяти

указывает указатель, а мы по условию определили переменную var1. Переменная определена и нет понятия указывает, есть понятия определена, куда её сунет компилятор по большому счету все равно, обращаться к ней мы будем по "var1", но тут вступают правила языка "Си" область видимости, расширение области видимости есть плохой тон(не мной придумано), поэтому иногда корректней передать не переменную(кстати тут вступают "блядские"(извиняюсь за свой французский) правила передачи), а указатель на переменную. Что я и сделал в строчке "array[1] =& var1;". Далее я произвел разименование " *(usbMsgPtr + 0) " для доступа к значению, почитайте понятие "разименования", и если Вам не станет понятна разница попробую объяснить я.

Скорей всего Вас смутила последовательность моих операций, по большому счету всё это начинает выглядеть красиво когда у нас много файловый проект.

>>equ т.к. создаются они очевидно в ОЗУ и не являются регистрами, +1 - потому что занимают 1 байт

Понятие регистр отсутствует в "СИ". В данном языке оперируют понятием переменных. ДА при разработке программы мы должны понимать что такое регистр, но компилятору такое понятие чуждо. Есть методы программирования позволяющие разместить переменные в регистрах, но сейчас не об этом разговор.

>>Если создавать переменные var1-varN независимо ...

Совершенно верно,но опять Вы не смотрите, что я пишу в программе

array[0] =& var0;
array[1] =& var1;
array[2] =& var2;
array[3] =& var3;
array[4] =& var4;

а массив определен как: unsigned char *array[5];

и указатели на переменные я разместил в нужных мне последовательностях.

Тут для новичков еще один подводный камень(сам долго не понимал), а на хрена оно надо (это честно)

Могу попробовать объяснить я, но лучше почитайте литературу и задайте вопросы. Я все же не учитель, а практик :D

Это сообщение поставляется "как есть", без каких либо гарантий. Автор сообщения не несёт какой либо ответственности

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

Ссылка на комментарий
Поделиться на другие сайты

Понятие регистр отсутствует в "СИ"
Да ну? В компьютерном Си возможно написать register char x; Вроде так, никогда не пользовался, в контроллерном тоже должно быть. Указание компилятору что переменную желательно сунуть в регистр. Если таких переменных нет, компилятор сам выбирает наиболее часто используемые. Как-то так.
unsigned char *array[5];

array[0] =& var0;

array[1] =& var1;

array[2] =& var2;

array[3] =& var3;

array[4] =& var4;

Только сейчас обратил внимание что это массив указателей. Которые занимают вдвое больше места чем сами переменные. Указатель же здесь 2 байта? Не проще сделать char *array=&v0;, но это сработает если v0-v4 идут последовательно. Зато места лишнего не занимает и адресация к array[x] идет как к элементу массива а не указателю, что конечно быстрее. Как в варианте Goodefine

uchar array[];

...

#define VAR1 array[1]

...

VAR1=.... //находим VAR1

...

usbMsgPtr = array;

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

>>Да ну? В компьютерном Си возможно написать register char x;

"register" - это не стандарт, а расширение языка в некоторых компиляторах. И означает она, просьбу к компилятору "по возможности разместить эту переменную в регистре" другими словами не дает 100% гарантию, что переменная будет находиться в регистре(регистров поди мало, а переменных много :D) В IAR для гарантированного размещения в регистрах периферии(если она не используется) можно делать вот так:

typedef struct SERVIСE
{
unsigned char temp:1;
unsigned char chenel1:1;
unsigned char chenel2:1;
}SERVIСE;
__no_init volatile SERVIСE service@0x2A; 

также можно задействовать регистры R1 - R15 включив соответствующие опции настройки компилятора. И использовать выше приведенную нотацию. Только используя соответствующий адрес регистра. По большому счету такой трюк для битовых переменных дает выигрыш как в размере кода так и в установке, сбросе и сравнении данной переменной, но расплата не совместимость данного кода с другими компиляторами.

На остальные Ваши высказывания отвечать на буду, потому что полностью с ними согласен. Скажу только, что по моему мнению при выборе алгоритма или возможностей языка всегда приходиться идти на компромисс. В данном случаи размер/скорость ну и в какой то мере стиль.

Изменено пользователем rtfcnf

Это сообщение поставляется "как есть", без каких либо гарантий. Автор сообщения не несёт какой либо ответственности

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

Ссылка на комментарий
Поделиться на другие сайты

не дает 100% гарантию
Еще бы! :-) Поскольку речь шла о компьютерном Си то там всего 2 регистра под это дело выделялось, если я ничего не забыл.

По теме: поскольку USB достаточно требовательный по ресурсам, не стоит разбрасываться тактами посылая за элементом массива через указатель.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

>> не стоит разбрасываться тактами посылая за элементом массива через указатель.

temp = *(usbMsgPtr + 0);

в IAR такой подход (не считая времени инициализации, но она проходит один раз и до обмена ) только добавит скорости

Изменено пользователем rtfcnf

Это сообщение поставляется "как есть", без каких либо гарантий. Автор сообщения не несёт какой либо ответственности

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

Ссылка на комментарий
Поделиться на другие сайты

Не могу согласиться. Пробовал компилировать простейший код по этому примеру и смотреть его ассемблерную реализацию. Компилировал AVR Studio смотрел ..\Default\file.lss Судя по содержимому это оно.

int main(){
arr[0]=&v0;
ldi	r24, 0x6A	; 106
ldi	r25, 0x00	; 0
sts	0x0061, r25
sts	0x0060, r24
arr[1]=&v1;
ldi	r24, 0x68	; 104
ldi	r25, 0x00	; 0
sts	0x0063, r25
sts	0x0062, r24
arr[2]=&v2;
ldi	r18, 0x6B	; 107
ldi	r19, 0x00	; 0
sts	0x0065, r19
sts	0x0064, r18
arr[3]=&v3;
ldi	r24, 0x69	; 105
ldi	r25, 0x00	; 0
sts	0x0067, r25
sts	0x0066, r24

v1=*(arr+2);
sts	0x0068, r18

return 0;
}

Лишние адреса почикал вручную. Обратите внимание на инициализацию arr[2]: используются регистры r18-r19 вместо r24-r25. Скорее всего это оптимизация и именно поэтому код выполняется за 2 такта. Я же говорил про общий случай - когда может не хватить свободных регистров. Тогда придется загружать в регистровую пару значение указателя а потом уже по регистровой паре значение переменной. Действительно, если вынести операцию присвоения за пределы main() получим 3 такта вместо 2-х:

.......................
sts	0x0064, r18
arr[3]=&v3;
ldi	r24, 0x69	; 105
ldi	r25, 0x00	; 0
sts	0x0067, r25
sts	0x0066, r24

v1=*(arr+2);
sts	0x0068, r18
calc();
return 0;
}

int calc(){
v2=*(arr+0);
 7c:	40 93 6b 00 	sts	0x006B, r20
arr[3]=&v3;

v1=*(arr+2);
calc();
return 0;
}
ldi	r24, 0x00	; 0
ldi	r25, 0x00	; 0
ret

00000086 <calc>:

int calc(){
v2=*(arr+0);
lds	r24, 0x0060
sts	0x006B, r24
}

P.S. что за int calc() сразу после main - не знаю, возможно еще одна оптимизация, но "честная" реализация - в конце.

P.P.S. 3 такта и 2 такта это из предположения что sts выполняется не за один такт а за 2, lds вроде за один такт.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

Ссылка на комментарий
Поделиться на другие сайты

А вот что сотворил IAR (оптимизатор выключен) как говориться почувствуйте разницу :D

  void main( void )
  {
MOV   	R22,R26  
SUBI  	R28,0x0A  	
array[0] =& var0;
MOV   	R16,R28   
SUBI  	R16,0xFC   
STD   	Y+5,R16 	
array[1] =& var1;
MOV   	R16,R28 
SUBI  	R16,0xFD 
STD   	Y+6,R16   
array[2] =& var2;
MOV   	R16,R28	
SUBI  	R16,0xFE  	
STD   	Y+7,R16	
array[3] =& var3;
MOV   	R16,R28 	
INC   	R16      	
STD   	Y+8,R16   
array[4] =& var4;
MOV   	R16,R28  
STD   	Y+9,R16	
usbMsgPtr = *array;
LDD   	R16,Y+5  	
MOV   	R26,R16 	

когда я пишу про программирования под AVR на "Си" я исхожу с точки зрения как транслирует IAR, поэтому наши выводы могут расходиться.

ИМХО:

IAR для AVR генирит самый быстрый и короткий код

Изменено пользователем rtfcnf

Это сообщение поставляется "как есть", без каких либо гарантий. Автор сообщения не несёт какой либо ответственности

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

Ссылка на комментарий
Поделиться на другие сайты

ИМХО:

IAR для AVR генирит самый быстрый и короткий код

А если присмотреться, то и самый кривой.

Последний листинг показывает размещение в массиве указателей на переменные. GCC честно взял адрес и поместил в массив:

arr[0]=&v0;

ldi r24, 0x6A ; 106

ldi r25, 0x00 ; 0

sts 0x0061, r25

sts 0x0060, r24

Теперь смотрим что сотворил IAR

array[0] =& var0;

MOV R16,R28

SUBI R16,0xFC

STD Y+5,R16

Быстро? Да. Коротко? Да. Правильно? НЕТ!

Указатель у АВР 16-ти битный, т.е. 2 байта. А вот IAR отчего-то считает не так. Он сохранил в массиве всего один байт. Есть правда вариант, что исходники отличались и массив для IAR был unsigned char. Тогда это ошибка программиста. Если же массивы объявлены одинаково, то увы - код от IAR неработоспособен. Кстати массив то явно вышел 8-ми битным, следующий указатель размещается по адресу Y+6....

А доступ к отдельным переменным через смещение вообще неверен в принципе. На момент компиляции адреса этих переменных неизвестны, их подставляет линкер уже в самом конце сборки проекта. Так что между var0 и var1 может например левый массив или структура лежать, расположенные по фиксированному адресу. Ну либо IAR настолько примитивен, что просто не позволяет свои секции в памяти создавать. GCC это умеет. В примере этот неверный прием достиг апогея - адрес взят от одной переменной и несмотря на то, что сами переменные друг с другом никак не связаны, IAR рассчитывает адрес очередной переменной так, будто они в массиве расположены.

В общем ИМХО очередной пример отвратительной кодогенерации от IAR.

Ссылка на комментарий
Поделиться на другие сайты

А доступ к отдельным переменным через смещение вообще неверен в принципе. На момент компиляции адреса этих переменных неизвестны, их подставляет линкер уже в самом конце сборки проекта. Так что между var0 и var1 может например левый массив или структура лежать, расположенные по фиксированному адресу. Ну либо IAR настолько примитивен...

Довольно наивное утверждение. Вы всерьез считаете, что нашли с первого просмотра такие огромные грабли, а разработчики компилятора и многочисленные программисты "не в курсе"? Почитайте про такой способ оптимизации как clustering variables... Когда компилятор после анализа кода размещает группу переменных вместе, лежащими подряд. Адрес вычисляется на основе адреса первой переменной группы + смещение. Это позволяет только один раз загрузить адрес в регистр, что и есть самая непосредственная экономия...

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

Ссылка на комментарий
Поделиться на другие сайты

Переменные могли бы быть объявлены вообще в разных модулях, собственно обычно это так и есть, иначе можно и нужно сразу их в массив/структуру собрать. Может конечно и IAR подсуетиться и преобразовать переменные в массив самостоятельно. Иногда это приводит к большому перерасходу ОЗУ (случай с переменными по фиксированным адресам)- остаются неиспользованные промежутки куда такой самосборный массив не лезет.

Но пусть так. Однако вопрос с размером указателя это не решает.

И допустим что компилятор собрал переменные в массив самостоятельно. Но отчего то не видно загрузки адреса первой переменной в индексный регистр. Он туда сам попадает? Это волшебство? Или все же предположения компилятора о физических адресах переменных? Сlustering variables все равно потребует загрузить адрес хотя бы один раз.

Правда непонятно зачем это вообще делать. STD Y+q 2 такта, STS тоже два. Второй случай не требует загрузки индексного регистра. Так что отбросив непонятности с размером указателя выходит все равно что у GCC код оптимальней. Хотя бы на загрузку этого индексного регистра, пусть это и два такта всего :)

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...