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

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

Отсюда появляются два решения:

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

Другие вопросы по тегам