|
указатель на тип void, попытки создать общую функцию |
|
|
|
Jan 3 2006, 13:06
|
Местный
  
Группа: Свой
Сообщений: 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 Или может еще каким образом поступают при такой задаче, просьба поделиться опытом ...
|
|
|
|
|
Jan 3 2006, 14:26
|
Местный
  
Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064

|
Цитата(IgorKossak @ Jan 3 2006, 18:15)  Всё, что Вы хотите легко реализуется перегружаемыми функциями в С++, а ещё элегантнее - шаблонной функцией. Давно так делаю и очень доволен. А если делать на С, то надо дополнительно передавать идентификатор типа и внутри универсальной функции делать приведение. Тогда и операция ++ будет работать. Попробовал sprintf() но сгенеренный код получился в 2 раза больше по времени выполнения. это если я Вас правильно понял всмысле перегружаемых. а что такое шаблонная функция ? В С я новичок, поэтому может какие термины еще не знаю  а разве Код (char*)pStr++; Это не приведение типа ? вот на такой вариант компилятор говорит: Error[Pe852]: expression must be a pointer to a complete object type как правильно написать чтобы ++ работал?
|
|
|
|
|
Jan 3 2006, 15:38
|

Гуру
     
Группа: Свой
Сообщений: 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*...}
.......... }
--------------------
|
|
|
|
|
Jan 3 2006, 15:50
|
Местный
  
Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064

|
Цитата(prottoss @ Jan 3 2006, 19:38)  В Си++ все это можно организовать, но все равно код раздуется до размеров двух процедур с разными типами данных.
Так что не убивайте время попусту преобразуйте VOID к переменной конкретного типа и все будет в порядке. Не бойтесь большого количества переменных в теле функции, шелуху компилятор сам откинет. ну в данном конкретном случае думаю код не очень увеличиться я думал это как раз через #if сделать, т.е. передаем указатель и смысл этого указателя S_F типа SRAM или FLASH. Цитата вот франмент варианта кода переделанной функции Идея о двух указателях была рассмотрена, и наверное я на ней остановлюсь  . но для полного понимания проблемы в будущем все таки почему Код (char*)pStr++; дает ошибку при компиляции ???
|
|
|
|
|
Jan 3 2006, 16:09
|
Местный
  
Группа: Свой
Сообщений: 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 можно переменную но это не совсем то что мне нужно. ... а по логике вроде должно работать, может логика неправильная ?
|
|
|
|
|
Jan 3 2006, 16:12
|
Профессионал
    
Группа: Свой
Сообщений: 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.
|
|
|
|
|
Jan 3 2006, 16:17
|

Гуру
     
Группа: Свой
Сообщений: 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 разная. Наверное, компилятор думает как я :-)
--------------------
|
|
|
|
|
Jan 3 2006, 16:27
|
Местный
  
Группа: Свой
Сообщений: 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, постоянно забываю указывать  Цитата возможно: Код c = *(char*)(pStr=(char*)pStr+1); так действительно работает, Спасибо. Цитата Все директивы препроцессора (которые с #) обрабатываются ещё _до_ компиляции. С помощью #if, Это я понимаю, меня как раз это и интересовало, чтобы код генерил препроцессор в зависимости от моих указаний. но вариант с __generic мне больше подходит.
|
|
|
|
|
Jan 3 2006, 17:08
|
Профессионал
    
Группа: Свой
Сообщений: 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.
|
|
|
|
|
Jan 3 2006, 18:04
|
Профессионал
    
Группа: Свой
Сообщений: 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.
|
|
|
|
|
Jan 4 2006, 07:36
|

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

|
Цитата(&-rey @ Jan 3 2006, 16:26)  Попробовал sprintf() но сгенеренный код получился в 2 раза больше по времени выполнения. это если я Вас правильно понял всмысле перегружаемых. Наверное, всё-таки, не по времени выполнения, а по объёму, да и то при полном отсутствии оптимизации. Почему-то никто не говорит (или я пропустил), что void* надо приводить не только к char*, но и к __flash char*. На это и указывает сообщение компилятора о незавершенном типе. Основная ошибка в том, что в функции на момент исполнения нет информации о том, какого типа указатель был приведен к void*. Решения было три: - тип __generic; - информация о типе указателя как аргумент в функции; - два указателя.
|
|
|
|
|
Jan 4 2006, 07:38
|
Местный
  
Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064

|
Цитата(SSerge @ Jan 3 2006, 21:08)  Код c = (char*)(pStr=(char*)pStr+1)[-1]; Но это уже натуральнейшее хакерство и должно выжигаться калёным железом... Уж лучше промежуточную переменную объявить. Спасибо SSerge за обяснения, мне как раз это счас очень нужно для понимания процесса. а что такое [-1] ? обещаю что никогда не применю это знание во вред  )) вот что получено в результате: Код 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++); } }
|
|
|
|
|
Jan 4 2006, 07:51
|
Местный
  
Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064

|
Цитата(IgorKossak @ Jan 4 2006, 11:36)  Наверное, всё-таки, не по времени выполнения, а по объёму, да и то при полном отсутствии оптимизации. возможно, я думал что она оптимизирована изначально, кроме того я сравнивал для варианта преобразования числа (перевода его в строку LCD) Цитата Почему-то никто не говорит (или я пропустил), что void* надо приводить не только к char*, но и к __flash char*. На это и указывает сообщение компилятора о незавершенном типе. c этого момента пожалуйста поподробнее... Цитата Основная ошибка в том, что в функции на момент исполнения нет информации о том, какого типа указатель был приведен к void*. но у меня ошибка была на этапе компиляции самой функции, а не в точке её вызова. Или это как-то взаимосвязвно ? Цитата Решения было три: - тип __generic; - информация о типе указателя как аргумент в функции; - два указателя. хотел применить 2-е но в результате остановился на 1-м.
|
|
|
|
|
Jan 4 2006, 08:28
|

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

|
Цитата(&-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. Но даже и без этого Ваш код будет неприятно больше и работать будет заметно медленнее.
|
|
|
|
|
Jan 4 2006, 09:36
|
Местный
  
Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064

|
Цитата(IgorKossak @ Jan 4 2006, 12:28)  ??? Вообще-то Вы сами это либо задаёте либо нет в настройках проекта. Да конечно, возможно я не так выразился. Я имел предположение что поскольку функция библиотечная то она уже написана оптимально, а оптимизация в свойствах проекта влиять будет только на мой код. В принципе это можно проверить. так и сделаю. Цитата Ошибка у Вас стилистическая. А то, о чем сообщает компилятор, об этом Вам уже говорили...... да это я уже понял. Цитата Насколько я помню тип __generic подразумевает также возможность указывания на __eeprom. Но даже и без этого Ваш код будет неприятно больше и работать будет заметно медленнее. ясно, это тоже проверю.
|
|
|
|
|
Jan 5 2006, 07:38
|
Местный
  
Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064

|
Цитата В принципе это можно проверить. так и сделаю. Привожу данные после исследования скорости выполнения и размера *.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 Комментировать не буду, дабы не быть уличенным в пропаганде
|
|
|
|
|
Jan 7 2006, 13:30
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(prottoss @ Jan 3 2006, 17:38)  Вы сами отвечаете на свой вопрос. В Си вы не сможете объеденить два разных указателя под одним пустым типом VOID. Компилятор просто не знает, как формировать инкремент для данного типа. Указатель на SRAM изменяется линейно, указатель на FLASH имеет немного отличный механизм инкремента. Во-первых это указатель содержит адрес не байта, как в SRAM мо, а слова, где младший бит адреса указывает на тип байта в слове (старший или младший). Вот это хит! ;> Дело в том, что если взять адрес слова, и сдвинуть его на 1 влево, а освободившийся младший бит использовать для адресации байта (старшего и младшего), то получится линейный указатель, точно такой же как тот, что адресует (по вашим словам) SRAM. И действительно физически это одна и та же регистровая пара Z.
|
|
|
|
|
Jan 7 2006, 20:51
|

Знающий
   
Группа: Свой
Сообщений: 697
Регистрация: 26-07-05
Из: Могилев
Пользователь №: 7 095

|
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
|
|
|
|
|
Jan 7 2006, 21:17
|

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

|
Цитата(defunct @ Jan 7 2006, 20:30)  Цитата(prottoss @ Jan 3 2006, 17:38)  Вы сами отвечаете на свой вопрос. В Си вы не сможете объеденить два разных указателя под одним пустым типом VOID. Компилятор просто не знает, как формировать инкремент для данного типа. Указатель на SRAM изменяется линейно, указатель на FLASH имеет немного отличный механизм инкремента. Во-первых это указатель содержит адрес не байта, как в SRAM мо, а слова, где младший бит адреса указывает на тип байта в слове (старший или младший).
Вот это хит! ;> Дело в том, что если взять адрес слова, и сдвинуть его на 1 влево, а освободившийся младший бит использовать для адресации байта (старшего и младшего), то получится линейный указатель, точно такой же как тот, что адресует (по вашим словам) SRAM. И действительно физически это одна и та же регистровая пара Z. Хит это или нет, но я и имел ввиду, что компилятор не знает, сдвигать указатель на бит или нет. Читайте внимательнее топики (или купите монитор многодюймовый)
--------------------
|
|
|
|
|
Jan 9 2006, 15:36
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(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.  В Вашей цитате не было написано того, о чем Вы сейчас говорите. Чтобы сказанное Вами было понятно не только Вам, а всем, я бы добавил, что указатели на Flash могут быть двух типов: 1. указатель на функцию - тогда флеш указатель указывает на СЛОВО (сдвинут на 1 вправо); 2. указатель на данные - тогда флеш указатель указывает на БАЙТ (линейный указатель как и при адресации SRAM). Согласитесь, что "указатель содержит адрес не байта, как в SRAM мо, а слова, где младший бит адреса указывает на тип байта в слове (старший или младший)" - фраза не совсем понятная и не раскрывает сути вопроса.
|
|
|
|
|
Jan 9 2006, 19:29
|

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

|
Цитата(defunct @ Jan 9 2006, 22:36)  "Не говорите мне что делать, и я не скажу Вам куда идти" © begin...end. В Вашей цитате не было написано того, о чем Вы сейчас говорите. Чтобы сказанное Вами было понятно не только Вам, а всем, я бы добавил, что указатели на Flash могут быть двух типов: 1. указатель на функцию - тогда флеш указатель указывает на СЛОВО (сдвинут на 1 вправо); 2. указатель на данные - тогда флеш указатель указывает на БАЙТ (линейный указатель как и при адресации SRAM). Согласитесь, что "указатель содержит адрес не байта, как в SRAM мо, а слова, где младший бит адреса указывает на тип байта в слове (старший или младший)" - фраза не совсем понятная и не раскрывает сути вопроса. Может быть я не совсем ясно выразился (я не читаю лекции студентам, я сам им не так давно был), но кто хотел, тот меня понял. "...В Вашей цитате не было написано того, о чем Вы сейчас говорите..." в ней не было сказано, но это подразумевалось. Вообще тема была поднята об указателях на языке Си. Я просто попытался как то объяснить людям, а Вы вместо того чтобы это же умно и доходчиво, что б всем понятно было, даже коровам, сразу объснить, флудить начали.
Сообщение отредактировал prottoss - Jan 9 2006, 19:56
--------------------
|
|
|
|
|
Jan 10 2006, 19:17
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 23-07-05
Пользователь №: 7 043

|
Я думаю неправильно говорить компилятор незнает или неумеет. По стандарту "C" обязан делать инкремент УКАЗАТЕЛЮ типа void и при этом безразлично как в конечном итоге интерпретируется адрес. Дело в том что архитектура AVR непозволяет этого сделать. Доступ, насколько я помню, к FLASH области и SRAM области совсем разные...
|
|
|
|
|
Jan 10 2006, 19:57
|

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

|
Цитата(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);
.....
--------------------
|
|
|
|
|
Jan 10 2006, 21:33
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 23-07-05
Пользователь №: 7 043

|
1. Если что-то кажется, я конечно извеняюсь, есть единственный выход - берем стандарт к примеру 99й и смотрим. 2. Можно приводить примеры работы со структурами, пайпами и.т.д, но ни я никто другой ничего об этом не говорил, а говорили об адресации. 3. Также, я не говорил что через указатель на void можно перескакивать через несколько байт, слов или элементов структур (применительно к их расположению в памяти) (хотя по стандарту для некоторых архитектур возможно), а адресация к ячейкам памяти - пожайлуста. 4. В этом топике обсуждались функции вывода СТРОК только из двух источников, а не чего-либо из структур (можно и строку расположить по три символа в разных частях SRAM - тогда все приведенные функции будут неверны). 5. К 1 вдогонку - попробуйте на любых других архитектурах (x86, PowerPC тотже ARM) сделать инкремент УКАЗАТЕЛЯ на void - и все ОК, для 86й на куче компиляторов, на PPC и ARM тоже все нормально (правда только под gcc пробовал).
И вдобавок, как я уже говорил, я склоняюсь к тому, что компилятор незнает какой именно доступ применять к тем или иным указателям т.к это указатель без типа (да и проверить нельзя, разве что только по верхним адресам для FLASH) и наверное из-за этого разработчики компилятора сделали генерацию ошибки в такой ситуации (вобщем чтоб легче жить).
То что я говорил, не меняет того факта, что сделать нормальную универсальную функцию нельзя, но всетаки... смысл то имеет разобраться в стандартах и как в таких случаях поступает компилятор...
|
|
|
|
|
Jan 11 2006, 07:19
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Цитата(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 (если этот код вообще скомпилируется, в чем есть большие сомнения  )? И как эту ситуацию описывает Стандарт - с ссылкой на конкретный пункт, пожалуйста.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Jan 11 2006, 07:55
|
Местный
  
Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064

|
to Old1: Спасибо, просмотрел Ваши функции, узнал для себя что unsigned char можно писать как строку символов без обьявления массива  кстати Вы в 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 прав  (по крайней с этим приходиться мириться) Вопрос об указатели на FLASH хоть и верен, но в данном варианте не имеет значения, т.к. ошибка инкремента приведенного указателя не зависит от типа приведения и возникает на стадии компиляции самой функции.
|
|
|
|
|
Jan 11 2006, 09:02
|
Участник

Группа: Участник
Сообщений: 16
Регистрация: 23-07-05
Пользователь №: 7 043

|
Ищем книгу "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' (внимательно читаем весь пункт) и понимаем что из себя представляет этот тип. Там же написано о том, что стандарт не может гарантировать наличия функциональности о которой я говорил по приведенным причинам.
|
|
|
|
|
Jan 11 2006, 16:22
|

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

|
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|/
--------------------
Зачем лаять на караван , когда на него можно плюнуть?
|
|
|
|
|
Jan 11 2006, 16:38
|
Местный
  
Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064

|
Цитата(_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, но возвращаться к ним не хочу  думаю и не придеться
Сообщение отредактировал &-rey - Jan 11 2006, 16:38
|
|
|
|
|
Jan 12 2006, 09:57
|

Знающий
   
Группа: Свой
Сообщений: 697
Регистрация: 26-07-05
Из: Могилев
Пользователь №: 7 095

|
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 (что-то уменя ввод гиперссылки не работает).
|
|
|
|
|
Jan 12 2006, 11:49
|
Местный
  
Группа: Свой
Сообщений: 298
Регистрация: 29-08-05
Пользователь №: 8 064

|
to Old1: Спасибо за ссылку, мои подозрения оправдались  Тему по __z_x скачал. Займусь на выходных.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|