реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> указатель на тип void, попытки создать общую функцию
andrvisht
сообщение Jan 3 2006, 13:06
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064



Всех с наступившим!!!
Решил написать функцию вывода строки в массив да так чтобы можно было эту строку брать как из 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
Или может еще каким образом поступают при такой задаче, просьба поделиться опытом ...
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Jan 3 2006, 14:15
Сообщение #2


Шаман
******

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



Всё, что Вы хотите легко реализуется перегружаемыми функциями в С++, а ещё элегантнее - шаблонной функцией.
Давно так делаю и очень доволен.
А если делать на С, то надо дополнительно передавать идентификатор типа и внутри универсальной функции делать приведение. Тогда и операция ++ будет работать.
Go to the top of the page
 
+Quote Post
andrvisht
сообщение Jan 3 2006, 14:26
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064



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

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

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

как правильно написать чтобы ++ работал?
Go to the top of the page
 
+Quote Post
prottoss
сообщение Jan 3 2006, 15:38
Сообщение #4


Гуру
******

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



Цитата(&-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*...}

..........
}


--------------------
Go to the top of the page
 
+Quote Post
andrvisht
сообщение Jan 3 2006, 15:50
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064



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

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

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

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

дает ошибку при компиляции ???
Go to the top of the page
 
+Quote Post
_artem_
сообщение Jan 3 2006, 15:58
Сообщение #6


учащийся
*****

Группа: Свой
Сообщений: 1 065
Регистрация: 29-10-05
Из: города контрастов
Пользователь №: 10 249



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.


--------------------
Зачем лаять на караван , когда на него можно плюнуть?

Go to the top of the page
 
+Quote Post
andrvisht
сообщение Jan 3 2006, 16:09
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064



Цитата(_artem_ @ Jan 3 2006, 19:58) *
sdelay tak :
c = *(((char*)pStr)++);

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

вместо 1 можно переменную
но это не совсем то что мне нужно.
... а по логике вроде должно работать, может логика неправильная ?
Go to the top of the page
 
+Quote Post
SSerge
сообщение Jan 3 2006, 16:12
Сообщение #8


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(&-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().

Сообщение отредактировал SSerge - Jan 3 2006, 16:14


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
prottoss
сообщение Jan 3 2006, 16:17
Сообщение #9


Гуру
******

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



[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 разная. Наверное, компилятор думает как я :-)


--------------------
Go to the top of the page
 
+Quote Post
_artem_
сообщение Jan 3 2006, 16:27
Сообщение #10


учащийся
*****

Группа: Свой
Сообщений: 1 065
Регистрация: 29-10-05
Из: города контрастов
Пользователь №: 10 249



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.


--------------------
Зачем лаять на караван , когда на него можно плюнуть?

Go to the top of the page
 
+Quote Post
andrvisht
сообщение Jan 3 2006, 16:27
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064



Цитата(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 мне больше подходит.
Go to the top of the page
 
+Quote Post
SSerge
сообщение Jan 3 2006, 17:08
Сообщение #12


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(&-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];

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


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
SSerge
сообщение Jan 3 2006, 18:04
Сообщение #13


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(&-rey @ Jan 3 2006, 21:50) *
но для полного понимания проблемы в будущем все таки почему
Код
(char*)pStr++;

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

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

P.S. Ну вот, пока объяснял, сам понял :-))


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Jan 4 2006, 07:36
Сообщение #14


Шаман
******

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



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

Наверное, всё-таки, не по времени выполнения, а по объёму, да и то при полном отсутствии оптимизации.
Почему-то никто не говорит (или я пропустил), что void* надо приводить не только к char*, но и к __flash char*. На это и указывает сообщение компилятора о незавершенном типе.
Основная ошибка в том, что в функции на момент исполнения нет информации о том, какого типа указатель был приведен к void*.
Решения было три:
- тип __generic;
- информация о типе указателя как аргумент в функции;
- два указателя.
Go to the top of the page
 
+Quote Post
andrvisht
сообщение Jan 4 2006, 07:38
Сообщение #15


Местный
***

Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064



Цитата(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++);
  }
}
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 16th June 2025 - 16:14
Рейтинг@Mail.ru


Страница сгенерированна за 0.01515 секунд с 7
ELECTRONIX ©2004-2016