|
|
  |
опять volatile |
|
|
|
Feb 9 2007, 22:46
|
Группа: Новичок
Сообщений: 11
Регистрация: 3-05-06
Пользователь №: 16 721

|
файл xxx.h typedef struct { unsigned char Isto; ... } TDataLbk; Прошу помочь. Пишется прога, состоящая из нескольких модулей.
файл xxx.c #include "xxx.h" volatile TDataLbk DataLbk; Именно здесь проводится заполнение этой структуры. volatile в xxx.c необходим для корректного проведения оптимизации, без неё компилятор выбрасывает DataLbk из конечного кода в файле main.c
файл main.c #include <string.h> #include "xxx.h" extern volatile TDataLbk DataLbk; DataLbk.Isto = 0x00; //без volatile компилятор выбрасывает эти действия memmove(&Obmen[chanl].Out.Data[4], &DataLbk, sizeof(TDataLbk)); На этой строке компилятор выдает ошибку: Error[Pe167]: argument of type "TDataLbk volatile *" is incompatible with parameter of type "void const *"
Вопросов два: 1. Как бороться с этой ошибкой. 2. какая из фу-ий memmov() или memcpy() быстрее в данной ситуации?
|
|
|
|
|
Feb 10 2007, 10:38
|
Группа: Новичок
Сообщений: 11
Регистрация: 3-05-06
Пользователь №: 16 721

|
Естественно здесь приведен не весь код, а лишь упрощенный фрагмент, показывающий суть проблемы. В main.c естествееноя я не обнуляю переменные на старте, но произвожу с ними (практически со всеми полями структуры DataLbk) минимальные действия, результат - при оптимизации эти строки выбрасываются (компилятор не понимает, что за счет этого ветвится алгоритм в других модулях) при отсутствии в объявлении volatile. Явное преобразование типов не проходит (хотя не понятно в какой тип преобразовывать, протатип объявлен как: void *memmove(void *s1, const void *s2, size_t n)  Насчет функций memmove(..) и memcpy(..) вопрос заключается в скорости работы этих функция конкретно для IAR, а не в том что они делают (это можно прочитать в help-е) За участие спасибо!
|
|
|
|
|
Feb 10 2007, 13:47
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(ПАВ @ Feb 10 2007, 09:38)  Насчет функций memmove(..) и memcpy(..) вопрос заключается в скорости работы этих функция конкретно для IAR IAR не IAR значения не имеет. Цитата , а не в том что они делают (это можно прочитать в help-е) Ну а после прочтения подумать, что в легче делать? Копировать произвольные области, либо еще гарантировать корректную работу при перекрытии областей? На счет всего остального непонятно зачем применено и/или как все в реальной программе смотрится.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Feb 11 2007, 00:15
|
Группа: Новичок
Сообщений: 11
Регистрация: 3-05-06
Пользователь №: 16 721

|
Прошу прощения за некорректную постановку вопроса. Попробую еще раз в более общем виде. Имеется два файла. В первом определяется переменная как volatile (см. стартовый постр). Во втором файле она же как extern volatile. Во втором файле необходимо вытащить значение переменной через её адрес (использую функцию memcpy(), указав в качестве аргумента адрес этой переменной). При этом выдается ошибка: Error[Pe167]: argument of type "TDataLbk volatile *" is incompatible with parameter of type "void const *". То же самое но без volatile компилируется без ошибок и предупреждений. Вопрос: как с этим бороться? Недопонимаю я суть volatile!
|
|
|
|
|
Feb 11 2007, 01:00
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(ПАВ @ Feb 11 2007, 02:15)  Вопрос: как с этим бороться? Недопонимаю я суть volatile! Суть квалификатора volatile в том, что он описывает переменную, которая может меняться вне данной конкретной функции или модуля. Например, в процедуре прерывания, вызов которой недетерменирован во времени. При операциях с переменной описанной как volatile компилятору запрещается использовать ее локальные копии. Т.е. компилятор обязан считывать каждый раз значение переменной с квалификатором volatile, несмотря на частоту использования ее в данной функции. По поводу ошибки. Если внимательно рассмотреть прототип функций memspy и memmov, то можно заметить, что указатель на источник данных описан как указатель на область данных константного типа ( const void *src). Таким образом во время выполнения указанных функций гарантируется что источник данных не может быть модифицирован. Квалификатор volatile противоречит этому условия, указывая на то, что источник данных может быть модифицирован в любое время и в т.ч. во время выполнения функций memspy/memmov. Поэтому компилятор вполне справедливо выдает сообщение об ошибке. P.S. Кстати, а явное приведение типов не прокатывает что ли? P.P.S. вот уж не думал, что даже с моими любительскими познаниями в Си можно уже читать лекции
|
|
|
|
|
Feb 11 2007, 10:23
|
Группа: Новичок
Сообщений: 11
Регистрация: 3-05-06
Пользователь №: 16 721

|
Цитата По поводу ошибки. Если внимательно рассмотреть прототип функций memspy и memmov, то можно заметить, что указатель на источник данных описан как указатель на область данных константного типа (const void *src). Таким образом во время выполнения указанных функций гарантируется что источник данных не может быть модифицирован. Квалификатор volatile противоречит этому условия, указывая на то, что источник данных может быть модифицирован в любое время и в т.ч. во время выполнения функций memspy/memmov. Поэтому компилятор вполне справедливо выдает сообщение об ошибке. Вот оно! Совершенно справедливо! Цитата P.P.S. вот уж не думал, что даже с моими любительскими познаниями в Си можно уже читать лекции Знания всегда прерывисты! Форум как раз и позволяет устранить пробелы, актуальные на данный момент. Цитата P.S. Кстати, а явное приведение типов не прокатывает что ли? Цитата В этом конкретном месте используйте явное приведение типов memcpy(dst, (void *)&TDataLbk, size). А при чем здесь приведение типов? Объявление аргумента в функции как void говорит о возможности подстановки любого типа. Оно и понятно. Копирование в ф-ии происходит по байтно (в общем случае пословно) значит любая переменная будет скопирована полнстью, с точностью до байта (простите за коламбур). Цитата А вот ставить volatile только чтобы компилятор не выкидывал - что-то тут неправильно. Не должен он выкидывать переменную и запись в нее если к этой переменной есть обращения в других файлах. Согласен, однако это так. Не выкидывается переменная если компилятор считает, что она влияет на результат выполнения функции, в которой используется (например в условии ветвления). А если просто поставить tmp++; или a = tmp; поверьте будет выкинута! В моем случае именно такой вариант. Переменная меняется в прерывании, а её значение присваивается в основной программе другой переменной. Цитата Она точно объявлена глобальной и не static? Точно!
|
|
|
|
|
Feb 11 2007, 11:59
|

Гуру
     
Группа: Свой
Сообщений: 3 041
Регистрация: 10-01-05
Из: Москва
Пользователь №: 1 874

|
Цитата(ПАВ @ Feb 9 2007, 22:46)  DataLbk.Isto = 0x00; //без volatile компилятор выбрасывает эти действия Где именно написана эта строчка? Цитата(ПАВ @ Feb 9 2007, 22:46)  2. какая из фу-ий memmov() или memcpy() быстрее в данной ситуации? memcpy всегда не медленнее. Но не везде её можно применять - только если source и destination не перекрываются. Цитата(ПАВ @ Feb 11 2007, 10:23)  А при чем здесь приведение типов? Объявление аргумента в функции как void говорит о возможности подстановки любого типа. Оно и понятно. Копирование в ф-ии происходит по байтно (в общем случае пословно) значит любая переменная будет скопирована полнстью, с точностью до байта (простите за коламбур). Неявное приведение типов никогда не отменяет volatile и const. Если есть желание - их нужно снимать явно.
--------------------
Пишите в личку.
|
|
|
|
|
Feb 11 2007, 18:30
|
Группа: Новичок
Сообщений: 11
Регистрация: 3-05-06
Пользователь №: 16 721

|
Цитата (ПАВ @ Feb 9 2007, 22:46)
DataLbk.Isto = 0x00; //без volatile компилятор выбрасывает эти действия
Где именно написана эта строчка? Строчка написана в качестве примера в main(), реально несколько другие действия. Суть - без volatile компилятор выбрасывает эти действия при оптимизации. Вообще долгое время писал на ASM и С использовал только для реализации математики, сам отслеживал что выбрасывать, а что нет. Мое мнение - компилятор не должен вмешиваться в алгоритмию (даже при оптимизации), написано где либо изменение произвольной глобальной переменной (например, tmp++  - значит так надо! Иначе можно зайти очень далеко, как у меня и получилось - писал и отлаживал без оптимизации протокол обмена. Отладился, для повышения эффективности необходимо было уменьшить время прерываний. Включил оптимизацию - все перестало работать. Выяснил часть кода выброшена! Хороша оптимизация! Цитата Неявное приведение типов никогда не отменяет volatile и const. Если есть желание - их нужно снимать явно. Если можно чуть подробнее, никогда не пользовался!
|
|
|
|
|
Feb 11 2007, 21:06
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(ПАВ @ Feb 11 2007, 20:30)  Цитата Неявное приведение типов никогда не отменяет volatile и const. Если есть желание - их нужно снимать явно. Если можно чуть подробнее, никогда не пользовался! Дык вы до сих пор не попробовали?  Попробуйте так Код memcpy(&Obmen[chanl].Out.Data[4], (const TDataLbk *)&DataLbk, sizeof(TDataLbk));
|
|
|
|
|
Feb 11 2007, 22:41
|
Группа: Новичок
Сообщений: 11
Регистрация: 3-05-06
Пользователь №: 16 721

|
Цитата Дык вы до сих пор не попробовали? Попробуйте так memcpy(&Obmen[chanl].Out.Data[4], (const TDataLbk *)&DataLbk, sizeof(TDataLbk)); Пробовал, но записывал неверно. Воспользовался Вашим (rezident) советом помогло. Всем огромное спасибо за оперативное участие! Тема раскрыта, просьба закрыть!
|
|
|
|
|
Feb 12 2007, 00:13
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(ПАВ @ Feb 11 2007, 22:41)  Цитата Дык вы до сих пор не попробовали? Попробуйте так memcpy(&Obmen[chanl].Out.Data[4], (const TDataLbk *)&DataLbk, sizeof(TDataLbk)); Тема раскрыта, просьба закрыть! Не, ну вот так всегда, на самом интересном месте  Вот я например так и не понял как это так, компилятор у Вас скушивал некоторые выражения/переменные которые дальше еще где-то используются. код покажите ? По поводу memcopy...итд Если Вам нужен действительно быстрый код, то тогда надо писать "ручками" типа так: unsigned char i=sizeof(TDataLbk); unsigned char *pS=(unsigned char *)&DataLbk; unsigned char *pD=(unsigned char *)&Obmen[chanl].Out.Data[4]; do { *pS++=*pD++; } while (--i); это будет не медленнее чем библиотечные memcpy единственно, если копирование нужно выполнять много раз в программе, то флешь будет расходоваться не очень эфективно... P.S. Кстати, можно сделать копирование еще быстрее, но это тема не этого топика ...
|
|
|
|
|
Feb 14 2007, 22:29
|
Группа: Новичок
Сообщений: 11
Регистрация: 3-05-06
Пользователь №: 16 721

|
Цитата Если Вам нужен действительно быстрый код, то тогда надо писать "ручками" типа так: unsigned char i=sizeof(TDataLbk); unsigned char *pS=(unsigned char *)&DataLbk; unsigned char *pD=(unsigned char *)&Obmen[chanl].Out.Data[4]; do { *pS++=*pD++; } while (--i); именно на таком (ну почти на таком) варианте я и остановился.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|