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&);

Но ссылки на энергонезависимое отношение к нелетучим неявным преобразованиям плохо сформированы.

Отсюда возникают два решения:

  1. не превращать изменчивые в энергонезависимые преобразования;
  2. определить подходящий конструктор копии или скопировать элементы объекта "вручную";
  3. 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&), который никогда не генерируется автоматически.