Доступ к профсоюзам в структуре - PullRequest
0 голосов
/ 03 марта 2019

Рассмотрим следующий код:

struct test1str
{
    int testintstr : 2;
    int testintstr2 : 1;
};

struct test2str
{
    int testintstr : 2;
    int testintstr2 : 1;
};

union test1uni
{
    int testint1;
    test1str str1;
};

union test2uni
{
    int testint2;
    test2str str2;
};

struct finalstruct
{
    test1uni union1;
    test2uni union2;
} finstr;

int* ptr = &finstr.union1.testint1;

finstr.union1.testint1 = 2;
finstr.union2.testint2 = 4;

cout << &finstr.union1 << endl;
cout << &finstr.union2 << endl;
printf("val: %i addr: %x\n", *ptr, ptr);
ptr++;
printf("val: %i addr: %x\n", *ptr, ptr);

Есть ли более подходящий способ доступа к значениям из объединений внутри примера finalstruct?Используя код из приведенного выше примера, я мог бы перебрать все объединения внутри "finalstruct" и получить int, который был необходим, но есть ли другой способ сделать это?

Предположим, что размер данных из всех структур будет меньшеили равный размеру переменной внутри объединения - структуры будут обрабатываться как битовые поля, а данные будут считываться через переменную объединения.

Это будет использоваться только на процессорах одного типа, скомпилированных с одним компилятором (gcc)и размеры всех структур и союзов будут одинаковыми (кроме окончательной конструкции, конечно).Я пытаюсь добиться того, чтобы можно было легко изменять разные биты с помощью struct (test1str, test2str), и для чтения мне нужно знать только то, какое окончательное значение получат эти биты - для этого я буду использовать union(test1uni, test2uni).Упаковав эти союзы в struct (finalstruct), я могу легко обработать все данные.

Ответы [ 2 ]

0 голосов
/ 03 марта 2019
ptr++

ptr не указывает на элемент массива, поэтому после его увеличения он становится недействительным - даже если в этом адресе есть другой объект.Когда вы проходите через него косвенно, поведение программы не определено.

Что вам действительно нужно для итерации членов класса, так это языковая функция, называемая «отражение».C ++ имеет очень ограниченную поддержку для отражения.Вы можете хранить ссылки на элементы в массиве и выполнять итерацию массива.Обратите внимание, что поскольку у нас не может быть массивов ссылок, нам нужно обернуть их, и в случае printf явно преобразовать оболочку обратно:

std::array members {
    std::ref(finstr.union1.testint1),
    std::ref(finstr.union2.testint2),
};
auto ptr = std::begin(members);

printf("val: %i addr: %p\n", ptr->get(), (void*)&ptr->get());
ptr++;
printf("val: %i addr: %p\n", ptr->get(), (void*)&ptr->get());

PS Я взял на себя смелость исправить printfвызов.%x неверно для указателя.

0 голосов
/ 03 марта 2019

Не думаю, что я полностью понял, чего вы пытаетесь достичь, но ...

Если вы уверены, что sizeof(test1uni) == sizeof(test2uni) == sizeof(int) и в структуре больше ничего нет, тогда выможет трактовать finalstruct как массив int s:

int *ptr = (int*)&finstr;
for(int i=0; i<sizeof(finstr)/sizeof(int); i++)
    printf("val: %i addr: %x\n", ptr[i], &ptr[i]);

Но, как уже упоминалось в комментариях, приведение структуры к типу int, вероятно, нарушает строгие псевдонимы и "наложение типа" с использованиемчлены union больше не разрешены явно в C ++ (в отличие от явно не разрешенных).Таким образом, это относится к области неопределенного поведения, поэтому вам необходимо:

  1. Отключить оптимизацию на основе строгого алиасинга.Например.передать -fno-strict-aliasing в GCC 3.4.1 и выше.Тем не менее, по-прежнему возникают проблемы с типами.
  2. Проверьте сборку, чтобы убедиться, что компилятор делает то, что вам нужно.
  3. Измените на C.

Такжепомните о других ошибках: int должно быть кратным слову, finstr должно быть выровнено по границе слова, компилятор / платформа должна следовать соглашению.Поэтому я бы не стал рассматривать этот портативный компьютер без более строгой строгости.

...