Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: указатель на тип void
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
andrvisht
Всех с наступившим!!!
Решил написать функцию вывода строки в массив да так чтобы можно было эту строку брать как из SRAM так и из FLASH а поскольку указатели на FLASH и SRAM это разные вещи, то и типы указателей должны быть разные.
решил сделать тип void чтобы тип можно было задать при вызове функции с приведением типа.

вот код функции
Код
void LCDString(unsigned char StrNum, unsigned char StrPos, void *pStr)
{
  unsigned char i, c;
  i = StrPos;
  c = *((char*)pStr++);
  while ((i < SYM_STR-2) && (c != 0x00))
  {
    LCDStr[StrNum][i] = c;
    c = *((char*)pStr++);
    i++;
  }
}

прблема в том что компилятор не может сделать ++ для указателя типа void.
если создать отдельную переменную типа char *pS; то все нормально.

т.о. вопрос ? как сделать ++ указателю типа void без отдельной переменной, если возможно.

И еще вопрос. Если нужен передавать параметр типа bool
то можно как-то использовать
#if
#endif
т.е. напрмер
Код
strcpy(char *pStr, bool S_F)
{
#if S_F // если передан указатель на FLASH
flashcpy()
#else
Sramcpy()
#endif
}

или может так :
Код
strcpy(char *pStr)
{
#ifdef S_F
flashcpy()
#else
Sramcpy()
#endif
}
а вызов функции делать так

#define S_F
strcpy(*pStr)
#undef S_F

Есть еще вариант передавать два указателя, для Flash и SRAM и ненужный передавать 0
Или может еще каким образом поступают при такой задаче, просьба поделиться опытом ...
IgorKossak
Всё, что Вы хотите легко реализуется перегружаемыми функциями в С++, а ещё элегантнее - шаблонной функцией.
Давно так делаю и очень доволен.
А если делать на С, то надо дополнительно передавать идентификатор типа и внутри универсальной функции делать приведение. Тогда и операция ++ будет работать.
andrvisht
Цитата(IgorKossak @ Jan 3 2006, 18:15) *
Всё, что Вы хотите легко реализуется перегружаемыми функциями в С++, а ещё элегантнее - шаблонной функцией.
Давно так делаю и очень доволен.
А если делать на С, то надо дополнительно передавать идентификатор типа и внутри универсальной функции делать приведение. Тогда и операция ++ будет работать.

Попробовал sprintf() но сгенеренный код получился в 2 раза больше по времени выполнения.
это если я Вас правильно понял всмысле перегружаемых.
а что такое шаблонная функция ?
В С я новичок, поэтому может какие термины еще не знаю sad.gif
а разве
Код
(char*)pStr++;

Это не приведение типа ? вот на такой вариант компилятор говорит:
Error[Pe852]: expression must be a pointer to a complete object type

как правильно написать чтобы ++ работал?
prottoss
Цитата(&-rey @ Jan 3 2006, 21:26) *
...а поскольку указатели на FLASH и SRAM это разные вещи, то и типы указателей должны быть разные


Вы сами отвечаете на свой вопрос. В Си вы не сможете объеденить два разных указателя под одним пустым типом VOID. Компилятор просто не знает, как формировать инкремент для данного типа. Указатель на SRAM изменяется линейно, указатель на FLASH имеет немного отличный механизм инкремента. Во-первых это указатель содержит адрес не байта, как в SRAM мо, а слова, где младший бит адреса указывает на тип байта в слове (старший или младший).

В Си++ все это можно организовать, но все равно код раздуется до размеров двух процедур с разными типами данных.

Так что не убивайте время попусту преобразуйте VOID к переменной конкретного типа и все будет в порядке. Не бойтесь большого количества переменных в теле функции, шелуху компилятор сам откинет.





вот франмент варианта кода переделанной функции
Код
void LCDString(unsigned char StrNum, unsigned char StrPos, char *pSramStr, char __flash *pFlashStr)
{    if(pSramStr) { ... приводим указатель в теле к char*...}

     if(pFlashStr){приводим указатель в теле к char __flash*...}

..........
}
andrvisht
Цитата(prottoss @ Jan 3 2006, 19:38) *
В Си++ все это можно организовать, но все равно код раздуется до размеров двух процедур с разными типами данных.

Так что не убивайте время попусту преобразуйте VOID к переменной конкретного типа и все будет в порядке. Не бойтесь большого количества переменных в теле функции, шелуху компилятор сам откинет.

ну в данном конкретном случае думаю код не очень увеличиться
я думал это как раз через #if сделать, т.е. передаем указатель и смысл этого указателя S_F типа SRAM или FLASH.
Цитата
вот франмент варианта кода переделанной функции

Идея о двух указателях была рассмотрена, и наверное я на ней остановлюсь smile.gif.
но для полного понимания проблемы в будущем все таки почему
Код
(char*)pStr++;

дает ошибку при компиляции ???
_artem_
sdelay tak :

c = *(((char*)pStr)++);

po moemu dolzno poyti .
Po idee dlya togo chto izmenit adres (inkrementirovat ego na odnu stupen posredstvom ++) C dolzen znat razmer tipa dannix dlja kotorogo vi sozdali ukazatel. Tak kak void* v sebe nichego razmernogo ne neset , kompailer vidaet osibku potomu chto ne znaet na kakoe znachenie uvelicit ukazatel. Dopustim esli tip dannix - byte , to address uvelichivaetsja na odin , esli short int to na dva . Poetomu increment vozmozen tolko posle castinga void na yavnij tip (v vasem sluchae - char), chto mi i pitaemsja delat posredstvom manipulyacii skobkami.
andrvisht
Цитата(_artem_ @ Jan 3 2006, 19:58) *
sdelay tak :
c = *(((char*)pStr)++);

Это второе что мне пришло в голову но:
Error[Pe137]: expression must be a modifiable lvalue
работает только
Код
c = *(((char*)pStr)+1);

вместо 1 можно переменную
но это не совсем то что мне нужно.
... а по логике вроде должно работать, может логика неправильная ?
SSerge
Цитата(&-rey @ Jan 3 2006, 19:06) *
Всех с наступившим!!!
Решил написать функцию вывода строки в массив да так чтобы можно было эту строку брать как из SRAM так и из FLASH а поскольку указатели на FLASH и SRAM это разные вещи, то и типы указателей должны быть разные.
решил сделать тип void чтобы тип можно было задать при вызове функции с приведением типа.

А компилятор какой? У IAR для AVR есть модификатор __generic для указателей.

Код
void LCDString(unsigned char StrNum, unsigned char StrPos, __generic char *pStr)

и передавайте в эту функцию хоть char*, хоть __flash char*, компилятор разберётся (и сделает необходимые преобразования типов при передаче параметров).
Цитата
прблема в том что компилятор не может сделать ++ для указателя типа void.
если создать отдельную переменную типа char *pS; то все нормально.

т.о. вопрос ? как сделать ++ указателю типа void без отдельной переменной, если возможно.

возможно:
Код
  c = *(char*)(pStr=(char*)pStr+1);

Впрочем, ничего страшного в использовании отдельной (auto) переменной нет - на то есть оптимизация.
Если эта переменная нигде больше не используется то и память под неё не будет выделяться, а регистры для вычислений (++) в любом случае будут использоваться.
Можно немного помочь оптимизатору указав для этой переменной модификатор register.
Цитата
И еще вопрос. Если нужен передавать параметр типа bool
то можно как-то использовать
#if
#endif

Все директивы препроцессора (которые с #) обрабатываются ещё _до_ компиляции. С помощью #if, #ifdef и т.п. можно выбрать какой кусок текста будет компилироваться а какой - нет, но эти директивы обрабатывает именно препроцессор, на вход собственно компилятору попадает _текст_ после препроцессора, т.е. в данном примере или строка flashcpy() или Sramcpy().
prottoss
[quote name='&-rey' date='Jan 3 2006, 22:50' post='75872']...я думал это как раз через #if сделать, т.е. передаем указатель и смысл этого указателя S_F типа SRAM или FLASH.
[quote]

Я думаю, Вы не совсем понимаете назначение директив условной компиляции. С помощью #if и других # вы не сделаете код гибче, Вы только сможете задать конкретный тип для входной переменной на этапе генерации кода.

[quote name='&-rey' date='Jan 3 2006, 22:50' post='75872']...но для полного понимания проблемы в будущем все таки почему
Код
(char*)pStr++;

дает ошибку при компиляции ??? [/quote]

Я уже объяснил Вам выше, что структура указателя для SRAM и FLASH разная. Наверное, компилятор думает как я :-)
_artem_
OK, v principe kompayler prav )), on ne mozet preobrazovat naverno tip ukazatelja .

Poprobuyte po drugomu - esli v svoej funkcii budete ispolzovat tolko kak char* to perepisite parametri funkcii vmesto void* na char* , tipa togo chto SSerge porekomendoval.
andrvisht
Цитата(SSerge @ Jan 3 2006, 20:12) *
А компилятор какой? У IAR для AVR есть модификатор __generic для указателей.
Код
void LCDString(unsigned char StrNum, unsigned char StrPos, __generic char *pStr)

и передавайте в эту функцию хоть char*, хоть __flash char*, компилятор разберётся (и сделает необходимые преобразования типов при передаче параметров).

Да компилятор IAR, постоянно забываю указывать smile.gif
Цитата
возможно:
Код
  c = *(char*)(pStr=(char*)pStr+1);

так действительно работает, Спасибо.
Цитата
Все директивы препроцессора (которые с #) обрабатываются ещё _до_ компиляции. С помощью #if,

Это я понимаю, меня как раз это и интересовало, чтобы код генерил препроцессор в зависимости от моих указаний. но вариант с __generic мне больше подходит.
SSerge
Цитата(&-rey @ Jan 3 2006, 22:27) *
Цитата(SSerge @ Jan 3 2006, 20:12) *

возможно:
Код
  c = *(char*)(pStr=(char*)pStr+1);

так действительно работает, Спасибо.


Тут я малость промахнулся, это аналог *++pStr а не *pStr++ как требовалось.
Нуууу..., тогда так
Код
  c = (char*)(pStr=(char*)pStr+1)[-1];

Но это уже натуральнейшее хакерство и должно выжигаться калёным железом...
Уж лучше промежуточную переменную объявить.
SSerge
Цитата(&-rey @ Jan 3 2006, 21:50) *
но для полного понимания проблемы в будущем все таки почему
Код
(char*)pStr++;

дает ошибку при компиляции ???

Выражение var++ эквивалентно var = var+1, НО:
Тут есть один тонкий момент - выражения в левой и правой части оператора присваивания вычисляются по-разному. В "С" они называются lvalue и rvalue.
В правой части вычисляется значение выражения (rvalue), при этом если в выражении есть имена переменных, т.е. символические имена для некоторых ячеек памяти, то используются значения этих переменных, числа, хранящиеся в соответствующих ячейках памяти.
При вычислении выражения в левой части (lvalue) на самом деле вычисляется адрес ячейки памяти куда следует поместить результат вычисления выражения в правой части.
Так вот (char*)pStr не может быть lvalue - нет такой ячейки памяти где бы оно хранилось.
Ситуация в точности такая-же как и для выражения (2*2)++;

P.S. Ну вот, пока объяснял, сам понял :-))
IgorKossak
Цитата(&-rey @ Jan 3 2006, 16:26) *
Попробовал sprintf() но сгенеренный код получился в 2 раза больше по времени выполнения.
это если я Вас правильно понял всмысле перегружаемых.

Наверное, всё-таки, не по времени выполнения, а по объёму, да и то при полном отсутствии оптимизации.
Почему-то никто не говорит (или я пропустил), что void* надо приводить не только к char*, но и к __flash char*. На это и указывает сообщение компилятора о незавершенном типе.
Основная ошибка в том, что в функции на момент исполнения нет информации о том, какого типа указатель был приведен к void*.
Решения было три:
- тип __generic;
- информация о типе указателя как аргумент в функции;
- два указателя.
andrvisht
Цитата(SSerge @ Jan 3 2006, 21:08) *
Код
  c = (char*)(pStr=(char*)pStr+1)[-1];

Но это уже натуральнейшее хакерство и должно выжигаться калёным железом...
Уж лучше промежуточную переменную объявить.


Спасибо SSerge за обяснения, мне как раз это счас очень нужно для понимания процесса.
а что такое [-1] ?
обещаю что никогда не применю это знание во вред smile.gif))

вот что получено в результате:
Код
void LCDString(unsigned char StrNum, unsigned char StrPos, unsigned char __generic *pStr)
{
  // Таблица перевода русских ASCI и псевдографики в коды ЖКИ
__flash static unsigned char RusConvTbl[] = { // Псевдографика (коды от 0x80 до 0xBF) };
  unsigned char    *pLCDStr, c;
  pLCDStr = LCDStr[StrNum] + StrPos;
  c = *(pStr++);
  while ((StrPos++ < SYM_STR-2) && (c != 0x00))
  {
    *pLCDStr++ = c;
    if (c < 0x80) *pLCDStr++ = c;
    else *pLCDStr++ = RusConvTbl[c - 0x80];
    c = *(pStr++);
  }
}
andrvisht
Цитата(IgorKossak @ Jan 4 2006, 11:36) *
Наверное, всё-таки, не по времени выполнения, а по объёму, да и то при полном отсутствии оптимизации.

возможно, я думал что она оптимизирована изначально, кроме того я сравнивал для варианта преобразования числа (перевода его в строку LCD)
Цитата
Почему-то никто не говорит (или я пропустил), что void* надо приводить не только к char*, но и к __flash char*. На это и указывает сообщение компилятора о незавершенном типе.

c этого момента пожалуйста поподробнее...
Цитата
Основная ошибка в том, что в функции на момент исполнения нет информации о том, какого типа указатель был приведен к void*.

но у меня ошибка была на этапе компиляции самой функции, а не в точке её вызова. Или это как-то взаимосвязвно ?
Цитата
Решения было три:
- тип __generic;
- информация о типе указателя как аргумент в функции;
- два указателя.

хотел применить 2-е но в результате остановился на 1-м.
IgorKossak
Цитата(&-rey @ Jan 4 2006, 09:51) *
Цитата(IgorKossak @ Jan 4 2006, 11:36) *

Наверное, всё-таки, не по времени выполнения, а по объёму, да и то при полном отсутствии оптимизации.

возможно, я думал что она оптимизирована изначально, кроме того я сравнивал для варианта преобразования числа (перевода его в строку LCD)

??? Вообще-то Вы сами это либо задаёте либо нет в настройках проекта.
Цитата(&-rey @ Jan 4 2006, 09:51) *
Цитата

Почему-то никто не говорит (или я пропустил), что void* надо приводить не только к char*, но и к __flash char*. На это и указывает сообщение компилятора о незавершенном типе.

c этого момента пожалуйста поподробнее...
Цитата
Основная ошибка в том, что в функции на момент исполнения нет информации о том, какого типа указатель был приведен к void*.

но у меня ошибка была на этапе компиляции самой функции, а не в точке её вызова. Или это как-то взаимосвязвно ?

Ошибка у Вас стилистическая. А то, о чем сообщает компилятор, об этом Вам уже говорили. Повторюсь.
Вы писали
Цитата
(char*)pStr++;
Это означает, что pStr постоянно хранится в памяти или в регистрах в изначальном виде (типе). Временно приводится к типу char*, изымается по нему значение, он инкрементируется (если ещё инкрементируется), а в каком виде его теперь хранить (какого он типа?)?
В таком случае и нужен промежуточный указатель (не факт, что в результате он будет не тем же самым), который инициализируется единожды
Цитата
char*spStr = (char*)pStr;
и в дальнейшем только он и используется.
Цитата(&-rey @ Jan 4 2006, 09:51) *
Цитата

Решения было три:
- тип __generic;
- информация о типе указателя как аргумент в функции;
- два указателя.

хотел применить 2-е но в результате остановился на 1-м.

Насколько я помню тип __generic подразумевает также возможность указывания на __eeprom. Но даже и без этого Ваш код будет неприятно больше и работать будет заметно медленнее.
andrvisht
Цитата(IgorKossak @ Jan 4 2006, 12:28) *
??? Вообще-то Вы сами это либо задаёте либо нет в настройках проекта.

Да конечно, возможно я не так выразился. Я имел предположение что поскольку функция библиотечная то она уже написана оптимально, а оптимизация в свойствах проекта влиять будет только на мой код. В принципе это можно проверить. так и сделаю.
Цитата
Ошибка у Вас стилистическая. А то, о чем сообщает компилятор, об этом Вам уже говорили......

да это я уже понял.
Цитата
Насколько я помню тип __generic подразумевает также возможность указывания на __eeprom. Но даже и без этого Ваш код будет неприятно больше и работать будет заметно медленнее.

ясно, это тоже проверю.
andrvisht
Цитата
В принципе это можно проверить. так и сделаю.

Привожу данные после исследования скорости выполнения и размера *.bin файла (всего проекта) для 4 MHz m128.
сравнил вывод числа 65535 в массив при помощи sprintf(LCD,"%hu", 0xffff); (Normal DLIB)
и при помощи FloatToLCD(0,0,65535.0,0,1);
sprintf
без опт. разм. 6442 байт и 62008.5us с макс опт. разм. 6436 байт и 62008.25us
без опт. скор. 6442 байт и 62008.5us с макс опт. скор. 6436 байт и 62008.25us
FloatToLCD
без опт. разм. 2220 байт и 2315us с макс опт. разм. 2072 байт и 2287.75us
без опт. скор. 2252 байт и 2303us с макс опт. скор. 2116 байт и 2262.75us
Цитата
ясно, это тоже проверю.

Вариант с одним указателем типа __generic для вычитки из SRAM
без опт. разм. 2345 байт и 117.75us с макс опт. разм. 2073 байт и 92us
без опт. скорости 2351 байт и 96.5us с макс опт. скор. 2059 байт и 71.5us

Вариант с одним указателем типа __generic для вычитки из FLASH
без опт. разм. 2348 байт и 120.75us с макс опт. разм. 2080 байт и 94.75us
без опт. скор. 2354 байт и 99.5us с макс опт. скор. 2060 байт и 74.25us

Вариант с двумя указателями для SRAM и FLASH и равенстве нулю FLASH.
без опт. разм. 2353 байт и 115us с макс опт. разм. 2067 байт и 115.75us
без опт. скор. 2373 байт и 92us с макс опт. скор. 2073 байт и 74.25us

Вариант с двумя указателями для SRAM и FLASH и равенстве нулю SRAM.
без опт. разм. 2354 байт и 125.5us с макс опт. разм. 2068 байт и 118.5us
без опт. скор. 2374 байт и 102.5us с макс опт. скор. 2074 байт и 82.5us

Комментировать не буду, дабы не быть уличенным в пропаганде smile.gif
defunct
Цитата(prottoss @ Jan 3 2006, 17:38) *
Вы сами отвечаете на свой вопрос. В Си вы не сможете объеденить два разных указателя под одним пустым типом VOID. Компилятор просто не знает, как формировать инкремент для данного типа. Указатель на SRAM изменяется линейно, указатель на FLASH имеет немного отличный механизм инкремента. Во-первых это указатель содержит адрес не байта, как в SRAM мо, а слова, где младший бит адреса указывает на тип байта в слове (старший или младший).


Вот это хит! ;>

Дело в том, что если взять адрес слова, и сдвинуть его на 1 влево, а освободившийся младший бит использовать для адресации байта (старшего и младшего), то получится линейный указатель, точно такой же как тот, что адресует (по вашим словам) SRAM. И действительно физически это одна и та же регистровая пара Z.
Old1
To &-rey.
Я тут для себя тоже провел кое-какие эксперименты по созданию универсальной функции чтения строк. В соответствии с предложенными выше IgorKossak вариантами решения написал три функции, каждая из которых читает сроку из SRAM/FLASH/EEPROM и записывает ее в SRAM (если интересно файлы проекта прилагаются). И для себя сделал вывод, что более подходящий второй вариант (информация о типе указателя как аргумент в функции) (в моем случае Funk1(…)). Во-первых, в моем случае он работает быстрее чем остальные варианты (за исключением чтения из флэш, тут немного быстрее функция с __generic). Во-вторых, этот вариант более универсальный в плане переносимости на другой компилятор (ИМХО квалификатор __generic поддерживается только ИАР-ом), и в плане доступа к различным типам памяти: как я понял __generic не работает с ЕЕПРОМ. Есть конечно и недостатки: второй вариант решения занимает несколько больше места в памяти программ (по сравнению с __generic) но с этим ИМХО можно мириться. Конечно результаты достаточно относительны и зависят от реализации. На всякий случай привожу результаты тестирования .
Информация о типе указателя как аргумент в функции ( функция Funk1):
чтение из SRAM – (макс. оптимиз. по р-ру) 345 цикл., (макс. оптимиз. по скорости)340цикл.
чтение из FLASH – (макс. оптимиз. по р-ру) 428 цикл., (макс. оптимиз. по скорости)426цикл.
чтение из EEPROM – (макс. оптимиз. по р-ру) 937 цикл., (макс. оптимиз. по скорости)938цикл.
Объем кода, макс. опт.по разм./ макс. опт. по скор. – 70/70

Использование квалификатора __generic (функцияFunk2):
чтение из SRAM – (макс. оптимиз. по р-ру) 387 цикл., (макс. оптимиз. по скорости)387цикл.
чтение из FLASH – (макс. оптимиз. по р-ру) 417 цикл., (макс. оптимиз. по скорости)417цикл.
чтение из EEPROM –не работает.
Объем кода, макс. опт.по разм./ макс. опт. по скор. – 44/44

Три указателя (функция Funk3):
чтение из SRAM – (макс. оптимиз. по р-ру) 389 цикл., (макс. оптимиз. по скорости)363цикл.
чтение из FLASH – (макс. оптимиз. по р-ру) 509 цикл., (макс. оптимиз. по скорости)481цикл.
чтение из EEPROM – (макс. оптимиз. по р-ру) 1085 цикл., (макс. оптимиз. по скорости)1057цикл.
Объем кода, макс. опт.по разм./ макс. опт. по скор. – 86/94
prottoss
Цитата(defunct @ Jan 7 2006, 20:30) *
Цитата(prottoss @ Jan 3 2006, 17:38) *

Вы сами отвечаете на свой вопрос. В Си вы не сможете объеденить два разных указателя под одним пустым типом VOID. Компилятор просто не знает, как формировать инкремент для данного типа. Указатель на SRAM изменяется линейно, указатель на FLASH имеет немного отличный механизм инкремента. Во-первых это указатель содержит адрес не байта, как в SRAM мо, а слова, где младший бит адреса указывает на тип байта в слове (старший или младший).


Вот это хит! ;>

Дело в том, что если взять адрес слова, и сдвинуть его на 1 влево, а освободившийся младший бит использовать для адресации байта (старшего и младшего), то получится линейный указатель, точно такой же как тот, что адресует (по вашим словам) SRAM. И действительно физически это одна и та же регистровая пара Z.


Хит это или нет, но я и имел ввиду, что компилятор не знает, сдвигать указатель на бит или нет. Читайте внимательнее топики (или купите монитор многодюймовый)
defunct
Цитата(prottoss @ Jan 7 2006, 23:17) *
Цитата(defunct @ Jan 7 2006, 20:30) *
Цитата(prottoss @ Jan 3 2006, 17:38) *

Вы сами отвечаете на свой вопрос. В Си вы не сможете объеденить два разных указателя под одним пустым типом VOID. Компилятор просто не знает, как формировать инкремент для данного типа. Указатель на SRAM изменяется линейно, указатель на FLASH имеет немного отличный механизм инкремента. Во-первых это указатель содержит адрес не байта, как в SRAM мо, а слова, где младший бит адреса указывает на тип байта в слове (старший или младший).


Вот это хит! ;>

Дело в том, что если взять адрес слова, и сдвинуть его на 1 влево, а освободившийся младший бит использовать для адресации байта (старшего и младшего), то получится линейный указатель, точно такой же как тот, что адресует (по вашим словам) SRAM. И действительно физически это одна и та же регистровая пара Z.


Хит это или нет, но я и имел ввиду, что компилятор не знает, сдвигать указатель на бит или нет. Читайте внимательнее топики (или купите монитор многодюймовый)


"Не говорите мне что делать, и я не скажу Вам куда идти" © begin...end. smile.gif

В Вашей цитате не было написано того, о чем Вы сейчас говорите. Чтобы сказанное Вами было понятно не только Вам, а всем, я бы добавил, что указатели на Flash могут быть двух типов:
1. указатель на функцию - тогда флеш указатель указывает на СЛОВО (сдвинут на 1 вправо);
2. указатель на данные - тогда флеш указатель указывает на БАЙТ (линейный указатель как и при адресации SRAM).

Согласитесь, что "указатель содержит адрес не байта, как в SRAM мо, а слова, где младший бит адреса указывает на тип байта в слове (старший или младший)" - фраза не совсем понятная и не раскрывает сути вопроса.
prottoss
Цитата(defunct @ Jan 9 2006, 22:36) *
"Не говорите мне что делать, и я не скажу Вам куда идти" © begin...end. smile.gif

В Вашей цитате не было написано того, о чем Вы сейчас говорите. Чтобы сказанное Вами было понятно не только Вам, а всем, я бы добавил, что указатели на Flash могут быть двух типов:
1. указатель на функцию - тогда флеш указатель указывает на СЛОВО (сдвинут на 1 вправо);
2. указатель на данные - тогда флеш указатель указывает на БАЙТ (линейный указатель как и при адресации SRAM).

Согласитесь, что "указатель содержит адрес не байта, как в SRAM мо, а слова, где младший бит адреса указывает на тип байта в слове (старший или младший)" - фраза не совсем понятная и не раскрывает сути вопроса.




Может быть я не совсем ясно выразился (я не читаю лекции студентам, я сам им не так давно был), но кто хотел, тот меня понял. "...В Вашей цитате не было написано того, о чем Вы сейчас говорите..." в ней не было сказано, но это подразумевалось. Вообще тема была поднята об указателях на языке Си. Я просто попытался как то объяснить людям, а Вы вместо того чтобы это же умно и доходчиво, что б всем понятно было, даже коровам, сразу объснить, флудить начали.
defunct
Цитата(prottoss @ Jan 9 2006, 21:29) *
а Вы вместо того чтобы это же умно и доходчиво, что б всем понятно было, даже коровам, сразу объснить, флудить начали.


Извините, в этом я был действительно неправ.
ObitJr
Я думаю неправильно говорить компилятор незнает или неумеет. По стандарту "C" обязан делать инкремент УКАЗАТЕЛЮ типа void и при этом безразлично как в конечном итоге интерпретируется адрес. Дело в том что архитектура AVR непозволяет этого сделать. Доступ, насколько я помню, к FLASH области и SRAM области совсем разные...
prottoss
Цитата(ObitJr @ Jan 11 2006, 02:17) *
Я думаю неправильно говорить компилятор незнает или неумеет. По стандарту "C" обязан делать инкремент УКАЗАТЕЛЮ типа void и при этом безразлично как в конечном итоге интерпретируется адрес. Дело в том что архитектура AVR непозволяет этого сделать. Доступ, насколько я помню, к FLASH области и SRAM области совсем разные...


А мне как раз кажется наоборот. И что серьезно "...По стандарту "C" обязан делать инкремент УКАЗАТЕЛЮ типа void и при этом безразлично как в конечном итоге интерпретируется адрес...". А как тогда, к примеру, Вы прокомментируете вот такой код:

Код
  

/* объявление структур */

typedef struct Struct1_type{

int a,b,c,d,e,f;

} Struct1;

typedef struct Struct2_type{

char a,b,c,d,e,f;

} Struct2;

/* объявление функций  и переменных*/

Struct1 Struct1_Array[10];

Struct2 Struct2_Array[10];

void MySuperFunc(void* ptr){

ptr++;

}

/* Где то в программе */

......

MySuperFunc(&Struct1_Array[0]);

......

MySuperFunc(&Struct2_Array[0]);

.....


Интересно, как MySuperFunc узнает, с каким типом данных ей работать? Размер одного типа данных отличается от другого в два раза. Прочитает исходник? Ей же кроме адреса массива ничего больше не передается! Вот если бы мы кроме указателя передавали еще одним параметром в функцию ее тип, то функция могла бы определить , с чем ей работать. Допустим примерно так:

Код
  

#define TYPE_STRUCT1 0

#define TYPE_STRUCT2 1

...

void MySuperFunc(void* ptr, char type){

if(type == TYPE_STRUCT1){

(Struct1*)ptr++;

}

if(type == TYPE_STRUCT2){

(Struct2*)ptr++;

}

}

/* Где то в программе */

......

MySuperFunc(&Struct1_Array[0], TYPE_STRUCT1);

......

MySuperFunc(&Struct2_Array[0], TYPE_STRUCT2);

.....
sensor_ua
указатель void, ИМХО, действительно не может знать величину приращения при любыхарифметических действиях с ним.
void MySuperFunc(void* ptr, char type){
Struct1* ptr1 = ptr;
Struct2* ptr2 = ptr;
if(type == TYPE_STRUCT1) ptr1++;
if(type == TYPE_STRUCT2) ptr2++;
}
ObitJr
1. Если что-то кажется, я конечно извеняюсь, есть единственный выход - берем стандарт к примеру 99й и смотрим.
2. Можно приводить примеры работы со структурами, пайпами и.т.д, но ни я никто другой ничего об этом не говорил, а говорили об адресации.
3. Также, я не говорил что через указатель на void можно перескакивать через несколько байт, слов или элементов структур (применительно к их расположению в памяти) (хотя по стандарту для некоторых архитектур возможно), а адресация к ячейкам памяти - пожайлуста.
4. В этом топике обсуждались функции вывода СТРОК только из двух источников, а не чего-либо из структур (можно и строку расположить по три символа в разных частях SRAM - тогда все приведенные функции будут неверны).
5. К 1 вдогонку - попробуйте на любых других архитектурах (x86, PowerPC тотже ARM) сделать инкремент УКАЗАТЕЛЯ на void - и все ОК, для 86й на куче компиляторов, на PPC и ARM тоже все нормально (правда только под gcc пробовал).

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

То что я говорил, не меняет того факта, что сделать нормальную универсальную функцию нельзя, но всетаки... смысл то имеет разобраться в стандартах и как в таких случаях поступает компилятор...
dxp
Цитата(ObitJr @ Jan 11 2006, 03:33) *
1. Если что-то кажется, я конечно извеняюсь, есть единственный выход - берем стандарт к примеру 99й и смотрим.
...
То что я говорил, не меняет того факта, что сделать нормальную универсальную функцию нельзя, но всетаки... смысл то имеет разобраться в стандартах и как в таких случаях поступает компилятор...

Что-то все равно не понятно. Отсылания к Стандартам, к сожалению, не проясняют ситуацию. Если уж ссылаетесь на Стандарт, то указывайте конкретный номер параграфа и пункта. А еще лучше прямо цитату сюда.

Я проще спрошу, хотя и тоже на примере (чтобы понятнее было). Вот имеем функцию:
Код
void f(void* p)
{
    *p++ = 10;
    *p++ = 20;
}


Условия следующие: пусть аппаратная платформа AVR программная EWAVR - все это означает, что

sizeof(char) == 1
sizeof(int) == 2
sizeof(long) == 4
sizeof(float) == 4
sizeof(void*) == 2
и т.д.

Теперь пусть имеем, скажем, массив

char A[64];

расположенный по адресу 0x100, и передаем его адрес в функцию:
...
f((void*)A);
...

Вопрос: по какому адресу запишется число 20 (если этот код вообще скомпилируется, в чем есть большие сомнения smile.gif)? И как эту ситуацию описывает Стандарт - с ссылкой на конкретный пункт, пожалуйста.
andrvisht
to Old1:
Спасибо, просмотрел Ваши функции, узнал для себя что unsigned char можно писать как строку символов без обьявления массива smile.gif
кстати Вы в def.h делаете так:
Код
#ifdef __FUNK1__
void Write_massiv_1(void *P_STRING, unsigned char *P_MASSIV, unsigned char STRING_TYPE);
#else
extern void Write_massiv_1(void *P_STRING, unsigned char *P_MASSIV, unsigned char STRING_TYPE);
#endif//__FUNK1__

в книге по С сказано:
Цитата
Если спецификатор класса памяти не указан, то подразумевается класс памяти extern.

т.о. можно сократить запись, чего нельзя сказать о переменных...

А вот если в функции с __generic переставить местами аргументы то результаты будут чуть лучьше.
366 цикл. и 405 цикл. соответственно.
Для void такое мероприятие в некоторых случаях даже ухудшает дело.

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

И еще такой вопрос:
У IAR по умолчанию функция main возвращает значение int = 0;
понятно что такого быть не должно, и она может быть void.
но ведь для чего-то IAR так делает, а иногда (причину пока не выяснил) IAR дает сообщение на main что возвращаемый тип должен быть int. ???
to ObitJr
абсолютно согласен, в книге по С такой пример есть. А в IAR нет, вот только после данной ветки мне теперь кажется что IAR прав smile.gif (по крайней с этим приходиться мириться)
Вопрос об указатели на FLASH хоть и верен, но в данном варианте не имеет значения, т.к. ошибка инкремента приведенного указателя не зависит от типа приведения и возникает на стадии компиляции самой функции.
ObitJr
Ищем книгу "The New C Standard - An economic and Cultural Commentary" (только не говорите чтоб я ее куда-нибуть запостил - ее можно найти в сети). В книге есть ссылки на стандарты и коментарии к ним.
Смотрим для начала пункт '6.2.5 Types' - в конце этого пункта написано практически тоже что я и говорил про то, что есть ситуации в которых невозможно определить какой применять доступ к некоторым облястям памяти. (Там же есть и пару строк про IAR, только применительно к PIC контроллерам)
Смотрим пункты '6.3.2.2 Void', '6.3.2.3 Pointers' (внимательно читаем весь пункт) и понимаем что из себя представляет этот тип. Там же написано о том, что стандарт не может гарантировать наличия функциональности о которой я говорил по приведенным причинам.
_artem_
esli vse taki xotite manipulirovat void v funkcii to mozete sdelat assemblernuju vstavku dlja inkrementa void'a v zavisimosti ot tipa .

Цитата
Ищем книгу "The New C Standard - An economic and Cultural Commentary" (только не говорите чтоб я ее куда-нибуть запостил - ее можно найти в сети). В книге есть ссылки на стандарты и коментарии к ним.


A kniga vrode by est v emule (imya poxozee )) ):
ed2k://|file|The%20New%20C%20Standard%20A%20Commentory.pdf|7964335|359B84821628646E0157EE8877E09211|/
andrvisht
Цитата(_artem_ @ Jan 11 2006, 20:22) *
esli vse taki xotite manipulirovat void v funkcii to mozete sdelat assemblernuju vstavku dlja inkrementa void'a v zavisimosti ot tipa .

Спасибо, я уже все сделал через __generic , и привел результаты выше.
раньше на ASM писал, потом на AlgBulder, но возвращаться к ним не хочу sad.gif думаю и не придеться smile.gif
Old1
To &-rey.
Цитата
А вот если в функции с __generic переставить местами аргументы то результаты будут чуть лучьше.
366 цикл. и 405 цикл. соответственно.

Да, действительно... спасибо.

Цитата
конечно оптимизировать можно до бесконечности ...

Еще одно замечание на эту тему, если в моем примере в модуле Funk1 в определении функции использовать квалификатор __x_z, то результаты тоже улучшаются , но к сожалению строка из flash (при таком построении функции) все равно читается медленнее чем с __generic...

Цитата
И еще такой вопрос:
У IAR по умолчанию функция main возвращает значение int = 0;
понятно что такого быть не должно, и она может быть void.
но ведь для чего-то IAR так делает, а иногда (причину пока не выяснил) IAR дает сообщение на main что возвращаемый тип должен быть int. ???


Здесь уже задавался подобный вопрос, вот ссылка на тему: http://electronix.ru/forum/index.php?showt...st=0?entry50424 (что-то уменя ввод гиперссылки не работает).
andrvisht
to Old1:
Спасибо за ссылку, мои подозрения оправдались smile.gif
Тему по __z_x скачал. Займусь на выходных.
Old1
Цитата(Old1 @ Jan 12 2006, 13:57) *
...если в моем примере в модуле Funk1 в определении функции использовать квалификатор __x_z, то результаты тоже улучшаются ...

Упс... В данном случае __x_z не дает , увы, никакого эффекта (работал поздно ночью, видимо улучшенный результат приглючился smile3046.gif )...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.