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