|
Прошу совета по индексам массивов |
|
|
|
Nov 6 2006, 03:02
|
Местный
  
Группа: Свой
Сообщений: 255
Регистрация: 17-08-06
Из: Москва
Пользователь №: 19 646

|
Есть такой вот код: Код 171 usb_buffer[usb_txtail++]=0x05; \ 00000094 9160.... LDS R22, usb_txtail \ 00000098 2F56 MOV R21, R22 \ 0000009A 9553 INC R21 \ 0000009C 9350.... STS usb_txtail, R21 \ 000000A0 E055 LDI R21, 5 \ 000000A2 E070 LDI R23, 0 \ 000000A4 01FB MOVW R31:R30, R23:R22 \ 000000A6 .... SUBI R30, LOW((-(usb_buffer) & 0xFFFF)) \ 000000A8 .... SBCI R31, (-(usb_buffer) & 0xFFFF) >> 8 \ 000000AA 8350 ST Z, R21 Изначально предполагалось, что так как usb_txtail unsigned char, то оно досчитает до 255 и начнет снова с нуля без всяких танцев с бубнами. А фиг... Если после этого вставить строчку: Код if (usb_txtail == 255) usb_txtail = 0; то все работает на ура. Если этой строчки нет - досчитав до 255, начинается какая-то свистопляска, оно выводит содержимое буфера еще раз... Есть какие-нить идеи на эту тему?
|
|
|
|
|
Nov 6 2006, 08:57
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(king2 @ Nov 6 2006, 06:02)  Если после этого вставить строчку: Код if (usb_txtail == 255) usb_txtail = 0; Если добавить эту строку, то элемент с индексом 255 никогда не будет записан. Осталось разобраться, почему эта запись все ломает. Может быть, буфер случайно объявлен как usb_buffer[255]?
|
|
|
|
|
Nov 6 2006, 09:38
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(king2 @ Nov 6 2006, 06:02)  Есть такой вот код: Изначально предполагалось, что так как usb_txtail unsigned char, то оно досчитает до 255 и начнет снова с нуля без всяких танцев с бубнами. А фиг... Если после этого вставить строчку: Код if (usb_txtail == 255) usb_txtail = 0; то все работает на ура. Если этой строчки нет - досчитав до 255, начинается какая-то свистопляска, оно выводит содержимое буфера еще раз... Есть какие-нить идеи на эту тему?  Есть два варианта: 1. usb_buffer[(unsigned char)(usb_txtail++)]=0x05; 2. usb_buffer[usb_txtail++ % 255]=0x05;
|
|
|
|
|
Nov 6 2006, 12:57
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(prottoss @ Nov 6 2006, 17:00)  НИКОГДА, если переменная объявлена как CHAR, компилятор не переделает ее в INT, LONG, LONLONG или FLOAT, если вы прямо ему об этом не укажите... "Никогда не говори ''никогда''"  А про приведение типов в языке СИ вы знаете? И что бывает в случае арифметических операций с числами разной разрядности, надеюсь тоже в курсе? Цитата из K&R (переводная, из библиотеки Мошкова). Глава 1.6. МассивыЦитата По определению перед проведением арифметических опера- ций, вовлекающих переменные типа CHAR и INT, все они преоб- разуются к типу INT, TAK что в арифметических выражениях пе- ременные типа CHAR по существу идентичны переменным типа INT. Еще раз предлагаю инкремент индекса вынести как отдельную операцию. У меня нет IAR for AVR, чтобы проверить получившийся результат на ассемблере.
|
|
|
|
|
Nov 6 2006, 13:51
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Вот еще в Википедии отыскал существенное (по-моему) замечание/комментарий, подходящее как раз для данного случая. Цитата Note that for addition and subtraction of integers and pointers, the value of the pointer is not adjusted by the integer amount, but is adjusted by the amount multiplied by the size (in bytes) of the type to which the pointer refers. One pointer may also be subtracted from another, provided they point to elements of the same array (or the position just beyond the end of the array). If you have a pointer that points to an element of an array, the index of the element is the result when the array name is subtracted from the pointer. Here's an example. Раздел 1.4 Pointers and Arrays.
|
|
|
|
|
Nov 6 2006, 14:50
|

Шаман
     
Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221

|
Цитата(king2 @ Nov 6 2006, 05:02)  А фиг... Что под этим подразумевается? В отладчике смотрели? Ведь судя по приведенному коду всё должно быть нормально. Или это в результате вставки того пресловутого условия? Приведите сгенерированный код с условием и без него.
|
|
|
|
|
Nov 6 2006, 16:27
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(rezident @ Nov 6 2006, 19:57)  Цитата(prottoss @ Nov 6 2006, 17:00)  НИКОГДА, если переменная объявлена как CHAR, компилятор не переделает ее в INT, LONG, LONLONG или FLOAT, если вы прямо ему об этом не укажите...
"Никогда не говори ''никогда''"  А про приведение типов в языке СИ вы знаете? И что бывает в случае арифметических операций с числами разной разрядности, надеюсь тоже в курсе? Вы читайте, не то что выделенно большими буквами, а все предложение) Когда мы приводим один тип к другому, мы УКАЗЫВАЕМ компилятору про тип, и, соответсвенно, разрядность переменой, тип которой мы приводим. Когда мы выполняем арифметические операции над числами разной разрядности, мы то же, неявно УКАЗЫВАЕМ компилятору на разрядность операции... А если компилятор начнет предполагать, что после инкремента какой то переменной может произойти переполнение разрядной сетки, то все переменные, в конечном итоге, у него превратятся в LONGLONGLONGLONGLONG..................... Для того, что бы проверить код, не обязательно иметь ИАР Си, возьмите от Борланда или Мелкософта... Цитата(rezident @ Nov 6 2006, 19:57)  Цитата из K&R (переводная, из библиотеки Мошкова). Глава 1.6. МассивыЦитата По определению перед проведением арифметических опера- ций, вовлекающих переменные типа CHAR и INT, все они преоб- разуются к типу INT, TAK что в арифметических выражениях пе- ременные типа CHAR по существу идентичны переменным типа INT. Еще раз предлагаю инкремент индекса вынести как отдельную операцию. У меня нет IAR for AVR, чтобы проверить получившийся результат на ассемблере. К сожалению, не читал данное произведение... И хотя инкремент индекса, в приципе тоже арифметическая операция, ИМХО никогда любой нормальный компилятор не преобразует индекс при инкременте в переменную бОльшей разрядности... Может быть только, если этот компилятор написан Вами)
--------------------
|
|
|
|
|
Nov 8 2006, 08:06
|
Местный
  
Группа: Свой
Сообщений: 278
Регистрация: 18-01-05
Из: Санкт-Петербург
Пользователь №: 2 031

|
Я вообще не понял в чём проблема! Цитата если после этого поставить строчку if (usb_txtail == 255) usb_txtail = 0; Получится Код usb_buffer[usb_txtail++]=0x05; if (usb_txtail == 255) usb_txtail = 0; судя по асм. листингу usb_txtail однобайтовая переменная, а значит добавленная строка вообще не влияет на результат, либо её добавляют не после "этого", а перед "этим"! Ну да ладно читаем дальше. Цитата начинается какая-то свистопляска, оно выводит содержимое буфера еще раз... А "оно" и должно выводить ещё раз! Индекс то обнулился!  Цитата И хотя инкремент индекса, в приципе тоже арифметическая операция Было сказано про арифметические операции в которых участвуют переменные разных типов
|
|
|
|
|
Nov 8 2006, 12:01
|
Частый гость
 
Группа: Свой
Сообщений: 94
Регистрация: 14-04-05
Из: Россия
Пользователь №: 4 130

|
Цитата(king2 @ Nov 6 2006, 06:02)  начинается какая-то свистопляска, оно выводит содержимое буфера еще раз... Есть какие-нить идеи на эту тему?  какая свистопляска? куда выводит? судя по коду на асме происходит циклическое заполнение массива по адресу usb_buffer+usb_txtail.
Сообщение отредактировал ARIM - Nov 8 2006, 12:05
|
|
|
|
|
Nov 9 2006, 23:58
|
Частый гость
 
Группа: Свой
Сообщений: 91
Регистрация: 26-01-06
Пользователь №: 13 668

|
Цитата(rezident @ Nov 6 2006, 15:57)  Цитата(prottoss @ Nov 6 2006, 17:00)  НИКОГДА, если переменная объявлена как CHAR, компилятор не переделает ее в INT, LONG, LONLONG или FLOAT, если вы прямо ему об этом не укажите...
"Никогда не говори ''никогда''"  Именно так. Цитата(rezident @ Nov 6 2006, 15:57)  Еще раз предлагаю инкремент индекса вынести как отдельную операцию. У меня нет IAR for AVR, чтобы проверить получившийся результат на ассемблере. У меня IAR есть, и по эти граблям я уже ходил в точно такой же ситуации - записи в кольцевой буфер. Индекс массива у IAR - int, даже если он объявлен как char[256]. В данном случае нужно писать так (если usb_txtail объявлен как char): usb_txtail++; usb_buffer[usb_txtail]=0x05; или так: usb_buffer[(usb_txtail++) & 0xff]=0x05;
|
|
|
|
|
Nov 10 2006, 12:19
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(sz36 @ Nov 10 2006, 06:58)  Цитата(rezident @ Nov 6 2006, 15:57)  Цитата(prottoss @ Nov 6 2006, 17:00)  НИКОГДА, если переменная объявлена как CHAR, компилятор не переделает ее в INT, LONG, LONLONG или FLOAT, если вы прямо ему об этом не укажите...
"Никогда не говори ''никогда''" Именно так. Цитата(rezident @ Nov 6 2006, 15:57)  Еще раз предлагаю инкремент индекса вынести как отдельную операцию. У меня нет IAR for AVR, чтобы проверить получившийся результат на ассемблере. У меня IAR есть, и по эти граблям я уже ходил в точно такой же ситуации - записи в кольцевой буфер. Индекс массива у IAR - int, даже если он объявлен как char[256]. В данном случае нужно писать так (если usb_txtail объявлен как char): usb_txtail++; usb_buffer[usb_txtail]=0x05; или так: usb_buffer[(usb_txtail++) & 0xff]=0x05; Бред какой то...Вы первый пост читали? Если нет, то я Вам настоятельно рекомендую...
--------------------
|
|
|
|
|
Nov 13 2006, 14:26
|
Местный
  
Группа: Свой
Сообщений: 255
Регистрация: 17-08-06
Из: Москва
Пользователь №: 19 646

|
Отвечаю сразу всем. Если вынести инкремент в отдельную операцию, получается вот что: Код 84 usb_txtail++; \ 00000026 .... LDI R30, LOW(usb_txtail) \ 00000028 .... LDI R31, (usb_txtail) >> 8 \ 0000002A 8100 LD R16, Z \ 0000002C 9503 INC R16 \ 0000002E 8300 ST Z, R16 85 usb_buffer[usb_txtail]=0x05; \ 00000030 E005 LDI R16, 5 \ 00000032 9120.... LDS R18, usb_txtail \ 00000036 E030 LDI R19, 0 \ 00000038 01F9 MOVW R31:R30, R19:R18 \ 0000003A .... SUBI R30, LOW((-(usb_buffer) & 0xFFFF)) \ 0000003C .... SBCI R31, (-(usb_buffer) & 0xFFFF) >> 8 \ 0000003E 8300 ST Z, R16 От (unsigned char) перед инкрементом или от & 0xFF ничего не меняется. "ОНО" не должно выводить буфер еще раз, потому что вывод написан вот так: Код while (usb_txhead != usb_txtail) { Usb_write_byte(usb_buffer[usb_txhead++]); } По идее, переход от 255 к нулю не должен ничем отличаться от перехода с 10 на 11, например. А фиг.. Даже если заполнять буфер просто инкрементом, то оно потихонечку досчитывает до 255, потом быстро выводит буфер еще раз (уже заполненный) и продолжает. Объявления переменных: Код volatile unsigned char usb_buffer[256]; volatile unsigned char usb_txhead; volatile unsigned char usb_txtail;
|
|
|
|
|
Nov 13 2006, 15:38
|
Местный
  
Группа: Свой
Сообщений: 255
Регистрация: 17-08-06
Из: Москва
Пользователь №: 19 646

|
Цитата(aaarrr @ Nov 13 2006, 17:57)  Цитата(king2 @ Nov 13 2006, 17:26)  "ОНО" не должно выводить буфер еще раз, потому что вывод написан вот так... ...Даже если заполнять буфер просто инкрементом, то оно потихонечку досчитывает до 255, потом быстро выводит буфер еще раз (уже заполненный) и продолжает.
То есть выходит, что проблема имеет место при выводе данных, а не при вводе? Получается, что так. Фишка в том, что блоки и ввода и вывода одинаковые, индекс вывода "догоняет" индекс ввода, пока они не станут равны. И тот и другой только увеличивается, так что по идее, если индекс ввода поменялся 255->0, то и индекс вывода должен поменяться так же (и вывести байтик). А оно так не происходит, вместо этого оно каким-то образом проскакивает через проверку равенства индексов и выводит по-новой весь буфер..
|
|
|
|
|
Nov 13 2006, 16:01
|

Гуру
     
Группа: Свой
Сообщений: 2 720
Регистрация: 24-03-05
Пользователь №: 3 659

|
Цитата(king2 @ Nov 13 2006, 22:38)  А оно так не происходит, вместо этого оно каким-то образом проскакивает через проверку равенства индексов и выводит по-новой весь буфер..  Люди! так и не возьму в толк что ВАМ не понятного? ЕСЛИ и индекс обьявлен, как 8-разрядная переменная, то, естественно, какой бы ни был длины массив, хоть 160 гбайт,выше границы 256 элементов массива, ВЫ не выйдите ни когда) Компилятор будет тупо увеличивать разрядность индекса, дополнением его до нужной разрядности дополнением нулей ПРИ ВЫЧИСЛЕНИИ АБСОЛЮТНОГО АДРЕСА ЭЛЕМЕНТА МАССИВА, НО при выходе индекса (при его инкременте-декременте) за пределы объявленной разрядности, индекс будет урезан до той разрядности, которую ВЫ указали компилятору. В крайнем случае, если компилятор посчитает, что есть НЕОДНОЗНАЧНОСТЬ, он (компилятор) предупредит ВАС соответсвующим предупреждением. Ну.
--------------------
|
|
|
|
|
Nov 13 2006, 21:25
|
Местный
  
Группа: Свой
Сообщений: 255
Регистрация: 17-08-06
Из: Москва
Пользователь №: 19 646

|
Посылательный код: Код //! writes byte in FIFO for current endpoint #define Usb_write_byte(byte) (UEDATX = (U8)byte) //! tests if endpoint write allowed #define Is_usb_write_enabled() (UEINTX&(1<<RWAL))
412 while (Is_usb_write_enabled() && (usb_txhead != usb_txtail)) { ^ Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement \ ??loop1: \ 0000028E 910000E8 LDS R16, 232 \ 00000292 2F10 MOV R17, R16 \ 00000294 FF15 SBRS R17, 5 \ 00000296 C014 RJMP ??exit \ 00000298 9100.... LDS R16, usb_txhead \ 0000029C 9110.... LDS R17, usb_txtail \ 000002A0 1701 CP R16, R17 \ 000002A2 F071 BREQ ??exit 413 Usb_write_byte(usb_buffer[usb_txhead++]); \ 000002A4 9100.... LDS R16, usb_txhead \ 000002A8 2F10 MOV R17, R16 \ 000002AA 9513 INC R17 \ 000002AC 9310.... STS usb_txhead, R17 \ 000002B0 E010 LDI R17, 0 \ 000002B2 01F8 MOVW R31:R30, R17:R16 \ 000002B4 .... SUBI R30, LOW((-(usb_buffer) & 0xFFFF)) \ 000002B6 .... SBCI R31, (-(usb_buffer) & 0xFFFF) >> 8 \ 000002B8 8100 LD R16, Z \ 000002BA 930000F1 STS 241, R16 \ 000002BE CFE7 RJMP ??loop1 415 } Вопрос нифига не в том, почему индекс становится 16-битным - тут-то понятно почему, потому что он становится индексом не массива, а памяти, а это как раз unsigned int  Вопрос в том, почему при переходе через 0 оно посылает еще один раз весь буфер. Отличать 0 от 256 символов в буфере не надо, предполагается, что такой ситуации не возникает, а если возникает, то и фиг с ней. В данном примере ее реально не возникает, всегда реальных данных меньше чем 64 байт.
|
|
|
|
|
Nov 14 2006, 06:48
|
Местный
  
Группа: Свой
Сообщений: 278
Регистрация: 18-01-05
Из: Санкт-Петербург
Пользователь №: 2 031

|
Цитата Вопрос в том, почему при переходе через 0 оно посылает еще один раз весь буфер. потому что при переходе через ноль (usb_txhead != usb_txtail) условие Код (usb_txhead != usb_txtail) вы приводили почти во всех примерах, а как меняется usb_txtail вы не показывали.
|
|
|
|
|
Nov 14 2006, 13:45
|
Местный
  
Группа: Свой
Сообщений: 255
Регистрация: 17-08-06
Из: Москва
Пользователь №: 19 646

|
Цитата(_Sam_ @ Nov 14 2006, 09:48)  Цитата Вопрос в том, почему при переходе через 0 оно посылает еще один раз весь буфер. потому что при переходе через ноль (usb_txhead != usb_txtail) условие Код (usb_txhead != usb_txtail) вы приводили почти во всех примерах, а как меняется usb_txtail вы не показывали. Здесь я написал как оно из буфера выводится (инкремент usb_txtail), в первом посте написал как в буфер запихивается (инкремент usb_txhead). Не понимаю, почему условие НЕРАВЕНСТВА должно по другому работать, если одна из сравниваемых переменных равна нулю.
|
|
|
|
|
Nov 15 2006, 06:43
|
Местный
  
Группа: Свой
Сообщений: 278
Регистрация: 18-01-05
Из: Санкт-Петербург
Пользователь №: 2 031

|
Могли бы и целиком код привести. И указать в этом целом куске что конкретно не работает. Вот попытался как-то обобщить то что вы писали. Код #include "stdio.h"
volatile unsigned char usb_buffer[256]; volatile unsigned char usb_txhead = 1; // начинаем вывод с первого элемента volatile unsigned char usb_txtail = 255; // чтобы при выполнении цикла usb_txtail == 0
int main( void ){ usb_buffer[usb_txtail++]=0x05; while (usb_txhead != usb_txtail) { // Is_usb_write_enabled() я убрал, т.к. не знаю что такое UEDATX и UEINTX printf("%i - %i\n",usb_buffer[usb_txhead++],usb_txhead); // функцию Usb_write_byte заменил на printf } return 0; } У меня всё работает и буфер выводится один раз несмотря на переполнение индекса! Компилятор и отладчик использовал IAR. Формат printf - medium.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|