|
|
  |
указатель на тип void, попытки создать общую функцию |
|
|
|
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 (если этот код вообще скомпилируется, в чем есть большие сомнения  )? И как эту ситуацию описывает Стандарт - с ссылкой на конкретный пункт, пожалуйста.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|