Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: опять volatile
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
ПАВ
файл 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() быстрее в данной ситуации?
rezident
Я не большой спец, но с IAR немного работал. unsure.gif
Зачем всю структуру объявлять как volatile? Укажите в описании типа, что именно элемент Isto имеет признак volatile, если это так важно. Поскольку структура DataLbk имеет глобальный тип, то и обнулять ее элементы не требуется. Они в соответствии со спецификацией языка Си автоматически уже почищены на этапе выполнения старт-апа. Насчет возникающей ошибки тоже вроде понятно. Используйте явное приведение типов. IAR это любит smile.gif
Про основное отличие указанных функций (одна может перекрывающиеся области копировать, другая не может) см. например,
http://www.linuxdoc.ru/manpages/man3/memmove.3.html
http://www.linuxdoc.ru/manpages/man3/memcpy.3.html
ПАВ
Естественно здесь приведен не весь код, а лишь упрощенный фрагмент, показывающий суть проблемы. В main.c естествееноя я не обнуляю переменные на старте, но произвожу с ними (практически со всеми полями структуры DataLbk) минимальные действия, результат - при оптимизации эти строки выбрасываются (компилятор не понимает, что за счет этого ветвится алгоритм в других модулях) при отсутствии в объявлении volatile.
Явное преобразование типов не проходит (хотя не понятно в какой тип преобразовывать, протатип объявлен как: void *memmove(void *s1, const void *s2, size_t n)wink.gif
Насчет функций memmove(..) и memcpy(..) вопрос заключается в скорости работы этих функция конкретно для IAR, а не в том что они делают (это можно прочитать в help-е)
За участие спасибо!
zltigo
Цитата(ПАВ @ Feb 10 2007, 09:38) *
Насчет функций memmove(..) и memcpy(..) вопрос заключается в скорости работы этих функция конкретно для IAR

IAR не IAR значения не имеет.
Цитата
, а не в том что они делают (это можно прочитать в help-е)

Ну а после прочтения подумать, что в легче делать? Копировать произвольные области,
либо еще гарантировать корректную работу при перекрытии областей?
На счет всего остального непонятно зачем применено и/или как все в реальной программе смотрится.
rezident
Если нужно просто проинициализировать структуру, то почему бы это не сделать на этапе ее объявления? Естественно компилятор выбрасывает ее из кода, "наблюдая" что структура лишь только инициализируется какими-то значениями, но ни один элемент ее в данном модуле не используется. Я, например, тоже не вижу смысла extern-ить структуру только для того, чтобы ее проинициализировать. Вижу два выхода из этой ситуации:
- либо инициализируйте структуру при ее объявлении;
- либо инициализируйте ее в том модуле, в котором она реально используется.

Приведение типов естественно нужно делать в соответствии с прототипом функции.
ПАВ
Прошу прощения за некорректную постановку вопроса. Попробую еще раз в более общем виде.
Имеется два файла. В первом определяется переменная как volatile (см. стартовый постр). Во втором файле она же как extern volatile. Во втором файле необходимо вытащить значение переменной через её адрес (использую функцию memcpy(), указав в качестве аргумента адрес этой переменной). При этом выдается ошибка: Error[Pe167]: argument of type "TDataLbk volatile *" is incompatible with parameter of type "void const *". То же самое но без volatile компилируется без ошибок и предупреждений.
Вопрос: как с этим бороться? Недопонимаю я суть volatile!
rezident
Цитата(ПАВ @ Feb 11 2007, 02:15) *
Вопрос: как с этим бороться? Недопонимаю я суть volatile!

Суть квалификатора volatile в том, что он описывает переменную, которая может меняться вне данной конкретной функции или модуля. Например, в процедуре прерывания, вызов которой недетерменирован во времени. При операциях с переменной описанной как volatile компилятору запрещается использовать ее локальные копии. Т.е. компилятор обязан считывать каждый раз значение переменной с квалификатором volatile, несмотря на частоту использования ее в данной функции.
По поводу ошибки. Если внимательно рассмотреть прототип функций memspy и memmov, то можно заметить, что указатель на источник данных описан как указатель на область данных константного типа (const void *src). Таким образом во время выполнения указанных функций гарантируется что источник данных не может быть модифицирован. Квалификатор volatile противоречит этому условия, указывая на то, что источник данных может быть модифицирован в любое время и в т.ч. во время выполнения функций memspy/memmov. Поэтому компилятор вполне справедливо выдает сообщение об ошибке.
P.S. Кстати, а явное приведение типов не прокатывает что ли?
P.P.S. вот уж не думал, что даже с моими любительскими познаниями в Си можно уже читать лекции smile.gif
Сергей Борщ
Цитата(ПАВ @ Feb 10 2007, 23:15) *
То же самое но без volatile компилируется без ошибок и предупреждений.
Вопрос: как с этим бороться? Недопонимаю я суть volatile!
В этом конкретном месте используйте явное приведение типов memcpy(dst, (void *)&TDataLbk, size). А вот ставить volatile только чтобы компилятор не выкидывал - что-то тут неправильно. Не должен он выкидывать переменную и запись в нее если к этой переменной есть обращения в других файлах. Она точно объявлена глобальной и не static?
ПАВ
Цитата
По поводу ошибки. Если внимательно рассмотреть прототип функций memspy и memmov, то можно заметить, что указатель на источник данных описан как указатель на область данных константного типа (const void *src). Таким образом во время выполнения указанных функций гарантируется что источник данных не может быть модифицирован. Квалификатор volatile противоречит этому условия, указывая на то, что источник данных может быть модифицирован в любое время и в т.ч. во время выполнения функций memspy/memmov. Поэтому компилятор вполне справедливо выдает сообщение об ошибке.

Вот оно! Совершенно справедливо!

Цитата
P.P.S. вот уж не думал, что даже с моими любительскими познаниями в Си можно уже читать лекции

Знания всегда прерывисты! Форум как раз и позволяет устранить пробелы, актуальные на данный момент.

Цитата
P.S. Кстати, а явное приведение типов не прокатывает что ли?

Цитата
В этом конкретном месте используйте явное приведение типов memcpy(dst, (void *)&TDataLbk, size).

А при чем здесь приведение типов? Объявление аргумента в функции как void говорит о возможности подстановки любого типа. Оно и понятно. Копирование в ф-ии происходит по байтно (в общем случае пословно) значит любая переменная будет скопирована полнстью, с точностью до байта (простите за коламбур).
Цитата
А вот ставить volatile только чтобы компилятор не выкидывал - что-то тут неправильно. Не должен он выкидывать переменную и запись в нее если к этой переменной есть обращения в других файлах.

Согласен, однако это так. Не выкидывается переменная если компилятор считает, что она влияет на результат выполнения функции, в которой используется (например в условии ветвления). А если просто поставить tmp++; или a = tmp; поверьте будет выкинута! В моем случае именно такой вариант. Переменная меняется в прерывании, а её значение присваивается в основной программе другой переменной.
Цитата
Она точно объявлена глобальной и не static?

Точно!
Oldring
Цитата(ПАВ @ 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 9 2007, 22:46)

DataLbk.Isto = 0x00; //без volatile компилятор выбрасывает эти действия



Где именно написана эта строчка?

Строчка написана в качестве примера в main(), реально несколько другие действия. Суть - без volatile компилятор выбрасывает эти действия при оптимизации. Вообще долгое время писал на ASM и С использовал только для реализации математики, сам отслеживал что выбрасывать, а что нет. Мое мнение - компилятор не должен вмешиваться в алгоритмию (даже при оптимизации), написано где либо изменение произвольной глобальной переменной (например, tmp++wink.gif - значит так надо! Иначе можно зайти очень далеко, как у меня и получилось - писал и отлаживал без оптимизации протокол обмена. Отладился, для повышения эффективности необходимо было уменьшить время прерываний. Включил оптимизацию - все перестало работать. Выяснил часть кода выброшена! Хороша оптимизация!

Цитата
Неявное приведение типов никогда не отменяет volatile и const. Если есть желание - их нужно снимать явно.

Если можно чуть подробнее, никогда не пользовался!
rezident
Цитата(ПАВ @ Feb 11 2007, 20:30) *
Цитата
Неявное приведение типов никогда не отменяет volatile и const. Если есть желание - их нужно снимать явно.

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

Дык вы до сих пор не попробовали? w00t.gif Попробуйте так
Код
memcpy(&Obmen[chanl].Out.Data[4], (const TDataLbk *)&DataLbk, sizeof(TDataLbk));
ПАВ
Цитата
Дык вы до сих пор не попробовали? Попробуйте так
memcpy(&Obmen[chanl].Out.Data[4], (const TDataLbk *)&DataLbk, sizeof(TDataLbk));

Пробовал, но записывал неверно. Воспользовался Вашим (rezident) советом помогло.
Всем огромное спасибо за оперативное участие!
Тема раскрыта, просьба закрыть!
singlskv
Цитата(ПАВ @ Feb 11 2007, 22:41) *
Цитата
Дык вы до сих пор не попробовали? Попробуйте так
memcpy(&Obmen[chanl].Out.Data[4], (const TDataLbk *)&DataLbk, sizeof(TDataLbk));

Тема раскрыта, просьба закрыть!

Не, ну вот так всегда, на самом интересном месте smile.gif

Вот я например так и не понял как это так, компилятор у Вас скушивал
некоторые выражения/переменные которые дальше еще где-то используются.
код покажите ?

По поводу 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. Кстати, можно сделать копирование еще быстрее, но
это тема не этого топика ...
ПАВ
Цитата
Если Вам нужен действительно быстрый код, то тогда надо писать "ручками"
типа так:
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);

именно на таком (ну почти на таком) варианте я и остановился.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.