Очистить только битовые поля членов структуры? - PullRequest
2 голосов
/ 31 марта 2020

У меня есть struct, например:

struct Foo {
    unsigned int id;
    unsigned int flag_1 : 1;
    unsigned int flag_2 : 1;
    unsigned int flag_3 : 1;
    // Some arbitrary number of further flags. Code is
    // automatically generated and number will vary.
    // Notably, it may be more than an int's worth.
    int some_data;
    float some_more_data;
    // ...
};

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

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

Редактировать:

Здесь есть похожий вопрос: Сбросить все биты в c битовом поле

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

Ответы [ 2 ]

7 голосов
/ 31 марта 2020

Просто используйте отдельный struct для флагов:

struct Foo_flags {
    unsigned int flag_1 : 1;
    unsigned int flag_2 : 1;
    unsigned int flag_3 : 1;
    // ...
};

struct Foo {
    unsigned int id;
    struct Foo_flags flags;
    int some_data;
    float some_more_data;
    // ...
};

Или даже более простой вложенный struct:

struct Foo {
    unsigned int id;

    struct {
        unsigned int flag_1 : 1;
        unsigned int flag_2 : 1;
        unsigned int flag_3 : 1;
        // ...
    } flags;

    int some_data;
    float some_more_data;
    // ...
};

Затем, позже в вашем коде:

struct Foo x;
// ...
x.flags.flag_1 = 1;
// ...
memset(&x.flags, 0, sizeof(x.flags));
4 голосов
/ 31 марта 2020

С некоторыми незначительными изменениями вы можете использовать макрос offsetof, чтобы найти начало и конец данных «флага» в структуре, а затем использовать memset, чтобы очистить соответствующую память. (Обратите внимание, что вы не можете использовать offsetof непосредственно в битовых полях, следовательно, добавление члена flag_beg!)

Вот рабочий пример:

#include <stdio.h>
#include <stddef.h>  // defines offsetof
#include <string.h>  // declares memset

struct Foo {
    unsigned int id;
    unsigned int flag_beg;    // Could be unsigned char to save space
    unsigned int flag_1 : 1;
    unsigned int flag_2 : 1;
    unsigned int flag_3 : 1;
    unsigned int flag_end;    // Could be unsigned char to save space
    // Some arbitrary number of further flags. Code is
    // automatically generated and number will vary.
    // Notably, it may be more than an int's worth.
    int some_data;
    float some_more_data;
    // ...
};

#define FBEG (offsetof(struct Foo, flag_beg))
#define FEND (offsetof(struct Foo, flag_end))

int main()
{
    struct Foo f;
    f.id = 3; f.flag_1 = 1; f.flag_2 = 0; f.flag_3 = 1;
    f.some_data = 33; f.some_more_data = 16.2f;

    printf("%u %u %u %u %d %f\n", f.id, f.flag_1, f.flag_2, f.flag_3, f.some_data, f.some_more_data);
    memset((char*)(&f) + FBEG, 0, FEND - FBEG);
    printf("%u %u %u %u %d %f\n", f.id, f.flag_1, f.flag_2, f.flag_3, f.some_data, f.some_more_data);
    return 0;
}
...