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

 
 
 
Reply to this topicStart new topic
> опять volatile
ПАВ
сообщение Feb 9 2007, 22:46
Сообщение #1





Группа: Новичок
Сообщений: 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() быстрее в данной ситуации?
Go to the top of the page
 
+Quote Post
rezident
сообщение Feb 10 2007, 01:42
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Я не большой спец, но с 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
Go to the top of the page
 
+Quote Post
ПАВ
сообщение Feb 10 2007, 10:38
Сообщение #3





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



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


Гуру
******

Группа: Свой
Сообщений: 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
Go to the top of the page
 
+Quote Post
rezident
сообщение Feb 10 2007, 17:56
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



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

Приведение типов естественно нужно делать в соответствии с прототипом функции.
Go to the top of the page
 
+Quote Post
ПАВ
сообщение Feb 11 2007, 00:15
Сообщение #6





Группа: Новичок
Сообщений: 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!
Go to the top of the page
 
+Quote Post
rezident
сообщение Feb 11 2007, 01:00
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 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. вот уж не думал, что даже с моими любительскими познаниями в Си можно уже читать лекции smile.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 11 2007, 01:12
Сообщение #8


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
ПАВ
сообщение Feb 11 2007, 10:23
Сообщение #9





Группа: Новичок
Сообщений: 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?

Точно!
Go to the top of the page
 
+Quote Post
Oldring
сообщение Feb 11 2007, 11:59
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 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. Если есть желание - их нужно снимать явно.


--------------------
Пишите в личку.
Go to the top of the page
 
+Quote Post
ПАВ
сообщение Feb 11 2007, 18:30
Сообщение #11





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



Цитата
(ПАВ @ Feb 9 2007, 22:46)

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



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

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

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

Если можно чуть подробнее, никогда не пользовался!
Go to the top of the page
 
+Quote Post
rezident
сообщение Feb 11 2007, 21:06
Сообщение #12


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



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

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

Дык вы до сих пор не попробовали? w00t.gif Попробуйте так
Код
memcpy(&Obmen[chanl].Out.Data[4], (const TDataLbk *)&DataLbk, sizeof(TDataLbk));
Go to the top of the page
 
+Quote Post
ПАВ
сообщение Feb 11 2007, 22:41
Сообщение #13





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



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

Пробовал, но записывал неверно. Воспользовался Вашим (rezident) советом помогло.
Всем огромное спасибо за оперативное участие!
Тема раскрыта, просьба закрыть!
Go to the top of the page
 
+Quote Post
singlskv
сообщение Feb 12 2007, 00:13
Сообщение #14


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(ПАВ @ 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. Кстати, можно сделать копирование еще быстрее, но
это тема не этого топика ...
Go to the top of the page
 
+Quote Post
ПАВ
сообщение Feb 14 2007, 22:29
Сообщение #15





Группа: Новичок
Сообщений: 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);

именно на таком (ну почти на таком) варианте я и остановился.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 18th July 2025 - 20:12
Рейтинг@Mail.ru


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