Когда использовать бит-поля в C? - программирование
Подтвердить что ты не робот

Когда использовать бит-поля в C?

На вопрос "зачем нам использовать битовые поля", при поиске в Google я обнаружил, что битовые поля используются для флагов. Теперь мне любопытно, разве это единственный способ практически использовать битовые поля? Нужно ли использовать битовые поля для экономии места?

Способ определения битового поля из книги:

struct {
unsigned int is_keyword : 1; 
unsigned int is_extern : 1; 
unsigned int is_static : 1;
} flags;

Почему мы используем int? Сколько места занято? Я запутался, почему мы используем int, но не short или что-то меньшее, чем int. Как я понимаю, в памяти занят только 1 бит, но не целое значение типа unsigned. Это правильно?

4b9b3361

Ответ 1

Теперь мне любопытно, [являются флагами] единственный способ использования битовых полей?

Нет, флаги не являются единственным способом использования битовых полей. Они также могут использоваться для хранения значений больше одного бита, хотя флаги более распространены. Например:

typedef enum {
    NORTH = 0,
    EAST = 1,
    SOUTH = 2,
    WEST = 3
} directionValues;

struct {
    unsigned int alice_dir : 2;
    unsigned int bob_dir : 2;
} directions;

Нужно ли использовать битовые поля для экономии места?

Поля бит сохраняют место. Они также позволяют упростить установку значений, не выровненных по байтам. Вместо бит-сдвига и использования побитовых операций мы можем использовать тот же синтаксис, что и установочные поля в struct. Это улучшает читаемость. С битовым полем вы можете написать

directions.bob_dir = SOUTH;

Однако, делая это вручную, вам нужно написать что-то вроде:

#define BOB_OFFSET 2
directions &= ~(3<<BOB_OFFSET); // clear Bob bits
directions |= SOUTH<<BOB_OFFSET;

Эта улучшенная читаемость, возможно, важнее, чем сохранение нескольких байтов здесь и там.

Почему мы используем int? Сколько места занято?

Занимается пространство целого int. Мы используем int, потому что во многих случаях это не имеет большого значения. Если для одного значения вы используете 4 байта вместо 1 или 2, ваш пользователь, вероятно, не заметит. Для некоторых платформ размер имеет большее значение, и вы можете использовать другие типы данных, которые занимают меньше места (char, short, uint8_t и т.д.).

Как я понимаю, только 1 бит занят в памяти, но не целое значение unsigned int. Правильно ли это?

Нет, это неверно. Весь unsigned int будет существовать, даже если вы используете только 8 его битов.

Ответ 2

Довольно хороший ресурс Бит-поля в C.

Основная причина заключается в уменьшении используемого размера. Например, если вы пишете:

struct {
    unsigned int is_keyword; 
    unsigned int is_extern; 
    unsigned int is_static;
} flags;

Вы будете использовать как минимум 3 * sizeof(unsigned int) или 12 байтов для представления 3 маленьких флагов, которые должны иметь только 3 бита.

Итак, если вы пишете:

struct {
    unsigned int is_keyword : 1; 
    unsigned int is_extern : 1; 
    unsigned int is_static : 1;
} flags;

Это использует то же пространство, что и один unsigned int, поэтому 4 байта. Вы можете бросить 32 однобитовых поля в структуру, прежде чем потребуется больше места.

Это своего рода эквивалент классического домашнего битового поля brew:

#define IS_KEYWORD 0x01
#define IS_EXTERN  0x02
#define IS_STATIC  0x04
unsigned int flags;

Но синтаксис битового поля более чистый, сравните:

if (flags.is_keyword)

против

if (flags & IS_KEYWORD)

и, очевидно, меньше подверженных ошибкам.

Ответ 3

Другим местом, где используются битовые поля, являются аппаратные регистры. Если у вас есть 32-битный регистр, где каждый бит имеет определенное значение, вы можете изящно описать его с помощью битового поля.

Такое битовое поле по своей сути зависит от платформы. В этом случае переносимость не имеет значения.

Ответ 4

Мы используем битовые поля в основном (хотя и не исключительно) для структур флагов - байты или слова (или, возможно, более крупные вещи), в которых мы пытаемся собрать небольшие (часто два состояния) части (часто связанные) информации.

В этих сценариях используются битовые поля, поскольку они правильно моделируют проблему, которую мы решаем: то, с чем мы имеем дело, на самом деле не является 8-битным (или 16-битным или 24-битным или 32-битным) числом, а скорее набор из 8 (или 16 или 24 или 32) связанных, но разных фрагментов информации.

Проблемы, которые мы решаем с помощью бит-полей, - это проблемы, при которых "упаковка" информации плотно имеет измеримые преимущества и/или "распаковка" информации не имеет наказания. Например, если вы выставляете 1 байт через 8 контактов, а биты с каждого булавка проходят через свою собственную шину, которая уже напечатана на доске, так что она ведет именно туда, где она должна была, то поле бит идеально. Преимущество в "упаковке" данных состоит в том, что его можно отправить за один раз (что полезно, если частота шины ограничена и наша операция зависит от частоты ее выполнения), а штраф за "распаковку" данных не существует (или существует, но стоит того).

С другой стороны, мы не используем битовые поля для булевых в других случаях, таких как нормальное управление потоками программ, из-за того, как обычно работают компьютерные архитектуры. Большинство обычных процессоров не любят извлекать один бит из памяти - им нравится извлекать байты или целые числа. Они также не любят обрабатывать биты - их инструкции часто работают на больших вещах, таких как целые числа, слова, адреса памяти и т.д.

Итак, когда вы пытаетесь работать с битами, это зависит от вас или от компилятора (в зависимости от того, на каком языке вы пишете), чтобы выписать дополнительные операции, которые выполняют бит-маскирование и разбивают структуру всего, кроме информации, которую вы на самом деле хотят работать. Если в "упаковке" информации нет (а в большинстве случаев нет), то использование битовых полей для булевых будет только вводить служебные данные и шум в вашем коде.

Ответ 5

почему нам нужно использовать битовые поля?

Если вы хотите сохранить некоторые данные, которые могут храниться меньше байта, эти данные могут быть связаны в структуре с использованием полей бит. Во встроенном слове: когда один 32-битный мир любого регистра имеет разное значение для другого слова, тогда вы также можете использовать бит файлы, чтобы сделать их более читаемыми.

Я обнаружил, что битовые поля используются для флагов. Теперь мне любопытно, это единственный способ использования битовых полей практически?

Нет, это не единственный способ. Вы можете использовать его и другим способом.

Нужно ли использовать битовые поля для экономии места?

Да.

Как я понимаю, только 1 бит занят в памяти, но не целое значение unsigned int. Правильно ли это?

НЕТ. Память может быть занята только в байтах.

Ответ 6

Хорошим применением было бы реализовать кусок для перевода в-from-base64 или любую неуравновесную структуру данных.

struct {
    unsigned int e1:6;
    unsigned int e2:6;
    unsigned int e3:6;
    unsigned int e4:6;
} base64enc; //I don't know if declaring a 4-byte array will have the same effect.

struct {
    unsigned char d1;
    unsigned char d2;
    unsigned char d3;
} base64dec;

union base64chunk {
    struct base64enc enc;
    struct base64dec dec;
};

base64chunk b64c;
//you can assign 3 characters to b64c.enc, and get 4 0-63 codes from b64dec instantly.

Этот пример немного наивен, так как base64 также должен рассматривать нулевое завершение (т.е. строку, которая не имеет длины l, так что l% 3 равно 0). Но работает как образец доступа к несвязанным структурам данных.

Другой пример: использование этой функции для разбивки заголовка TCP-пакета на его компоненты (или другого заголовка пакета сетевого протокола, который вы хотите обсудить), хотя это более продвинутый и меньший пример для конечного пользователя, В целом: это полезно для внутренних ПК, SO, драйверов, систем кодирования.

Другой пример: анализ числа float.

struct _FP32 {
    unsigned int sign:1;
    unsigned int exponent:8;
    unsigned int mantissa:23;
}

union FP32_t {
    _FP32 parts;
    float number;
}

(Отказ от ответственности: не знаю имя файла/имя типа, где это применяется, но в C это объявлено в заголовке; не знаю, как это можно сделать для 64-битных флешек, поскольку мантисса должна иметь 52 бит и в 32-битных целевых ints имеют 32 бита).

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

Ответ 7

Чтобы ответить на исходный вопрос "Когда использовать бит-поля в C?"... согласно книге "Write Portable Code" Брайана Хука (ISBN 1-59327-056-9, я читал немецкое издание ISBN 3- 937514-19-8) и личного опыта:

НИКОГДА не используйте идиому битполя языка C, но делайте это самостоятельно.

Множество деталей реализации специфичны для компилятора, особенно в сочетании с объединениями, и все вещи не гарантируются в отношении разных компиляторов и различной endianess. Если есть только небольшой шанс, что ваш код должен быть портативным и будет скомпилирован для разных архитектур и/или с разными компиляторами, не используйте его.

У нас был этот случай при переносе кода с небольшого эндианского микроконтроллера с некоторым проприетарным компилятором на другой большой микроконтроллер с контроллером GCC, и это было не весело.: -/

Вот как я использую флаги (host byte order;-)) с тех пор:

# define SOME_FLAG        (1 << 0)
# define SOME_OTHER_FLAG  (1 << 1)
# define AND_ANOTHER_FLAG (1 << 2)

/* test flag */
if ( someint & SOME_FLAG ) {
    /* do this */
}

/* set flag */
someint |= SOME_FLAG;

/* clear flag */
someint &= ~SOME_FLAG;

Нет необходимости в объединении с типом int и некоторой структурой битового поля. Если вы прочитаете много встроенного кода, те тесты, настройки и четкие шаблоны станут обычным явлением, и вы легко их заметите в своем коде.

Ответ 8

Бит-поля могут использоваться для сохранения объема памяти (но использование бит-поля для этой цели встречается редко). Он используется там, где есть ограничение памяти. например) при программировании во встроенных системах.

Но это следует использовать только в случае крайней необходимости.

Потому что мы не можем иметь адрес битового поля. Поэтому оператор адреса & не может использоваться с ними.

Ответ 9

Вы можете использовать их для расширения числа беззнаковых типов, которые обертываются. Обычное вы бы имели только 8,16,32,64..., но вы можете иметь каждую власть с битовыми полями.

struct a
{
    unsigned int b : 3 ;
} ;

struct a w = { 0 } ;

while( 1 )
{
    printf("%u\n" , w.b++ ) ;
    getchar() ;
}

Ответ 10

Чтобы ответить на части вопроса, никто не ответил:

Ints not Shorts

Причина использования int, а не коротких сообщений и т.д. заключается в том, что в этом случае пространство не будет сохранено.

Современные компьютеры имеют 32- или 64-битную архитектуру и 32 или 64 бита будут необходимы, даже если вы используете меньший тип хранилища, например короткий.

Меньшие типы полезны только для сохранения памяти, если вы можете собрать их вместе (например, короткий массив может использовать меньше памяти, чем массив int, поскольку шорты могут быть собраны вместе в массиве). В большинстве случаев при использовании битовых полей это не так.

Другие использования

Битвые поля чаще всего используются для флагов, но есть и другие вещи, для которых они используются. Например, одним из способов представления шахматной доски, используемой во множестве шахматных алгоритмов, является использование 64-битного целого числа для представления платы (8 * 8 пикселей) и установки флагов в этом целой части, чтобы обеспечить положение всех белых пешек. Еще одно целое отображает всех черных пешек и т.д.

Ответ 11

Бит-поля гораздо более компактны, и это преимущество.

Но не забывайте, что упакованные структуры медленнее, чем обычные структуры. Их также сложнее построить, поскольку программист должен определить количество бит для использования для каждого поля. Это недостаток

Ответ 12

Чтобы использовать пространство памяти, мы можем использовать битовые поля.

Насколько я знаю в программировании реального мира, если мы требуем, мы можем использовать булевы вместо объявления его целыми числами, а затем создавать поле бит.

Ответ 13

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

Ответ 14

Почему мы используем int? Сколько места занято?

Один ответ на этот вопрос, который я не видел в любом из других ответов, заключается в том, что стандарт C гарантирует поддержку int. В частности:

В битовом поле должен быть тип, который является квалифицированной или неквалифицированной версией _Bool, подписанным int, unsigned int или каким-либо другим определенным определением типа.

Обычно компиляторы допускают дополнительные типы бит-полей, но не требуются. Если вы действительно обеспокоены переносимостью, int - лучший выбор.