volatile struct = struct невозможна, почему?
struct FOO{
int a;
int b;
int c;
};
volatile struct FOO foo;
int main(void)
{
foo.a = 10;
foo.b = 10;
foo.c = 10;
struct FOO test = foo;
return 0;
}
Это не скомпилируется, потому что struct FOO test = foo;
генерирует ошибку:
ошибка: привязка ссылки типа 'const FOO&' к 'volatile FOO' отменяет квалификаторы
Как я могу скопировать volatile struct
в другой struct
в C++ (до C++11)?
Многие люди предлагали просто удалить volatile, но я не могу сделать это в этом случае, потому что я хочу скопировать текущие настройки SPI-Reg в микроконтроллере, и это объявляется энергозависимым в заголовках производителя. Я хочу скопировать эти настройки, потому что производитель также предоставляет библиотеку для использования SPI для EnDat-Communication, и у меня нет доступа к исходному коду. Так как мне нужно изменить настройки SPI-Reg во время выполнения, я хочу легко вернуться к SPI-настройкам библиотеки без повторного вызова init_endat()-lib fkt (что не произойдет, если я вызову его дважды).
Могу ли я использовать memcopy() для этого?
Как и предполагалось, это копия следующего вопроса.
Почему мне не предоставляется конструктор копирования по умолчанию из volatile?
3 ответа
Это плохо сформировано, потому что FOO
имеет неявный конструктор копирования, определенный как:
FOO(FOO const&);
А ты пишешь FOO test = foo;
с foo
типа volatile FOO
, ссылаясь на:
FOO(volatile FOO const&);
Но ссылки на энергонезависимые ссылки на энергонезависимые неявные преобразования не имеют четкой формы.
Отсюда появляются два решения:
- не превращайте энергозависимые в энергонезависимые преобразования;
- определить подходящий конструктор копирования или скопировать элементы объекта "вручную";
const_cast
Можно удалить спецификатор volatile, но это неопределенное поведение, которое можно использовать, если ваш базовый объект эффективно изменчив.
Могу ли я использовать memcopy() для этого?
Нет, ты не можешь, memcpy
несовместим с изменчивыми объектами: у него нет перегрузки, которая принимает указатели на изменчивые объекты, и вы ничего не можете сделать, не вызывая неопределенное поведение.
Итак, в заключение, ваш лучший снимок, если вы не можете добавить конструктор в FOO
это определить:
FOO FOO_copy(FOO volatile const& other)
{
FOO result;
result.a = other.a;
result.b = other.b;
result.c = other.c;
return result;
}
Или с C++11 std::tie
:
FOO FOO_copy(FOO volatile const& other)
{
FOO result;
std::tie(result.a, result.b, result.c) = std::tie(other.a, other.b, other.c);
return result;
}
Чтобы дать другой подход к ответу, рассмотреть, почему это не имеет смысла, а не просто там, где стандарт C++ говорит, что это неверно:
Весь смысл volatile
в том, что у вас есть точный контроль над тем, какая переменная будет доступна, когда. Это означает, что дано volatile int i, j;
, i = 1; j = 2;
а также j = 2; i = 1;
не делай то же самое. Компилятор не может свободно преобразовывать одно в другое. То же относится и к чтению: дано volatile int i, j; int x, y;
, x = i; y = j;
а также y = j; x = i;
не делай то же самое. Наличие volatile
означает, что доступ должен происходить именно в указанном вами порядке.
Теперь, в вашем примере, что должно struct FOO test = foo;
делать? Вы никогда не указали, хотите ли вы сначала прочитать foo.a
, затем foo.b
, в конце концов foo.c
или, возможно, сначала прочитайте foo.c
, затем foo.b
, в конце концов foo.a
или, может быть, какой-то другой заказ.
Вы можете, если хотите, сделать это:
struct FOO test;
test.a = foo.a;
test.b = foo.b;
test.c = foo.c;
Здесь вы явно указываете порядок доступа к foo
поля, так что вы избежите проблемы.
Вы не предоставили достаточно информации о своей проблеме, чтобы дать более точную оценку, но решение любой проблемы, которую вы пытаетесь решить, почти наверняка не использовать volatile
, "Изменчивый" означает, что значение может измениться из-под ваших ног: два типичных хороших варианта использования - это переменные, измененные в обработчиках сигналов UNIX и отображаемых в памяти регистрах. Волатильности недостаточно для переменных, особенно для потоков.
Причина, по которой вы получаете эту ошибку, в том, что ваш компилятор пытается найти FOO(volatile FOO&)
конструктор копирования, который никогда не генерируется автоматически.