значение членов союзов с битовыми полями - PullRequest
2 голосов
/ 06 мая 2019

Я пытаюсь узнать, как распределяется память для союзов, содержащих битовые поля.

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

1.

union Example
{ int i:2;
  int j:9; 
};


int main(void)
{ 
   union Example ex;
   ex.j=15;
   printf("%d",ex.i);
}

Вывод: -1

2.

union Example
{ unsigned int i:2;
  int j:9; 
};


int main(void)
{ 
   union Example ex;
   ex.j=15;
   printf("%d",ex.i);
}

Вывод:3

Может кто-нибудь объяснить, пожалуйста, вывод?Это просто стандартный вывод для таких случаев?Я использую встроенный компилятор GCC в Unbuntu

Ответы [ 2 ]

1 голос
/ 06 мая 2019

Пример1

#include <stdio.h>

union Example
{ int i:2;
  int j:9; 
};


int main(void)
{ 
   union Example ex;
   ex.j=15;
   printf("%d",ex.i);
   printf("\nSize of Union : %lu\n" , sizeof(ex));

   return 0;
}

Вывод:

-1
Size of Union : 4

Наблюдения:

Из этого вывода мы можем сделать вывод, что даже если мы используем 9 бит (макс.), Компилятор выделяет 4 байта (из-за заполнения).Оператор union Example ex; выделяет 4 байта памяти для объекта Пример Пример.Оператор ex.j=15; назначает 0x0000000F этим 4 байтам памяти.Таким образом, для j он выделяет 0-0-0-0-0-1-1-1-1 для 9 битов.Оператор printf("%d",ex.i); пытается напечатать ex.i (что составляет 2 бита).У нас есть 1-1 из предыдущего оператора.

Здесь есть интересная часть, ex.i имеет тип подписанного int.Следовательно, первый бит используется для назначения подписанного представления, и большинство процессоров делает подписанное представление в форме дополнения до 2.Поэтому, если мы сделаем обратное дополнение 2 к 1-1, мы получим значение 1. Таким образом, мы получим выходное значение -1. ​​

Example2

#include <stdio.h>

union Example
{ unsigned int i:2;
  int j:9; 
};


int main(void)
{ 
   union Example ex;
   ex.j=15;
   printf("%d",ex.i);


   return 0;
}

Вывод:

3

Наблюдения:

Оператор union Example ex; выделяет 4 байта памяти для объекта-примера Union ex.Оператор ex.j=15; назначает 0x0000000F этим 4 байтам памяти.Таким образом, для j он выделяет 0-0-0-0-0-1-1-1-1 для 9 битов.оператор printf("%d",ex.i); пытается напечатать ex.i (что составляет 2 бита).У нас есть 1-1 из предыдущего оператора.

То же, что и в примере выше, но здесь ex.i имеет тип unsigned int.Следовательно, здесь не используется бит со знаком для представления.Поэтому все, что хранится в 2-битном расположении, является точным значением.Следовательно, результат равен 3.

Надеюсь, я очистил ваши сомнения.Пожалуйста, проверьте на 2 и 1 дополнения в Интернете.

0 голосов
/ 06 мая 2019

То, как ваш компилятор выделяет биты для битовых полей в объединении, перекрывает младшие биты j с битами i.Таким образом, когда j установлено в 15, каждый из двух битов i устанавливается в 1.

Когда i представляет собой двухбитовое целое число со знаком, объявленное с помощью int i:2, ваш компиляторинтерпретирует его как число двоичного дополнения до двух.При такой интерпретации биты 11 представляют -1.

Когда i представляет собой двухразрядное целое число без знака, объявленное с unsigned int i:2, оно является чисто двоичным, без знакового бита.С этой интерпретацией биты 11 представляют 3.

Программа ниже показывает, что установка двухбитового целого числа со знаком в -1 или двухбитового целого числа без знака в 3 приводит к тому же битовому шаблону в объединении, вминимум в вашей реализации на Си.

#include <stdio.h>


int main(void)
{
    union Example
    {
        unsigned u;
        int i : 2;
        int j : 9;
        unsigned int k : 2;
    } ex;

    ex.u = 0;
    ex.i = -1;
    printf("ex.i = -1:  %#x.\n", ex.u);

    ex.u = 0;
    ex.j = 15;
    printf("ex.j = 15:  %#x.\n", ex.u);

    ex.u = 0;
    ex.k = 3;
    printf("ex.k =  3:  %#x.\n", ex.u);
}

Вывод:

ex.i = -1:  0x3.
ex.j = 15:  0xf.
ex.k =  3:  0x3.

Обратите внимание, что компилятор может также распределять биты от старшего к младшему вместо младшего к старшему, в которомВ этом случае старшие биты j будут перекрываться с i вместо младших битов.Кроме того, компилятор может использовать блоки памяти другого размера для девяти битов j, чем для двухбитовых i, и в этом случае их биты могут вообще не перекрываться.(Например, он может использовать один 8-битный байт для i, но использовать 32-битное слово для j. Восьмибитный байт будет перекрывать некоторую часть 32-битного слова, но не обязательно частьиспользуется для j.)

...