LINUX.ORG.RU

как найти маску битового поля структуры?

 , ,


0

2

предположим, есть структура из одного байта, для простоты:

'''cpp strict a {

uint8_t a0 : 1;

uint8_t a1 : 6;

uint8_t a2 : 1;

} '''

всё в pragma pack, понятное дело

задача: найти битовую маску любого поля, не имея объекта структуры. т.е. как offsetof, только для бит: нужно узнать маску или offset+size, что одно и то же в данном случае



Последнее исправление: luntik2012 (всего исправлений: 1)

Не использовать битовые поля, использовать маски явно.

anonymous
()

Вот суть, допили под себя

typedef struct
{uint8_t a0:1;
 uint8_t a1:1;
 uint8_t a2:1;
}byte_t;

typedef union
{byte_t  byte;
 uint8_t mask;
}byte_u;

uint8_t byte_t_to_uint8(byte_t  byte)
{ byte_t lb = {.byte=byte};
  return lb.mask;
}

byte_t uint8_to_byte_t(uint8_t value)
{ byte_t lb = {.mask=value};
  return lb.byte;
}

LINUX-ORG-RU ★★★★★
()
Последнее исправление: LINUX-ORG-RU (всего исправлений: 1)

А почему нужно не иметь объекта структуры? Можно как-то так, но не гарантирую что тут нет UB (вспоминать грабли говносей нет никакого желания).

#include <stdio.h>
#include <stdint.h>
#include <string.h>

struct a {
    uint8_t a0 : 1;
    uint8_t a1 : 6;
    uint8_t a2 : 1;
};

int main() {
    struct a dummy = {};
    dummy.a1 = ~dummy.a1;

    char mask;
    memcpy(&mask, &dummy, 1);

    fprintf(stderr, "0x%0x\n", mask);
}

А так-то правильный вариант, как уже сказали, сразу использовать сдвиги и битовые операции для десереализации из потока байт.

slovazap ★★★★★
()
Ответ на: комментарий от slovazap

Битовые поля - это UB. Керниган и Ричи рекомендуют битовые маски.

LongLiveUbuntu ★★★★★
()

как найти маску битового поля структуры?

В общем случае - никак.

LongLiveUbuntu ★★★★★
()

Если нужно в compile-time:

  • и переносимо, то никак.
  • если не переносимо, то есть примерно две тактики укладки битовых полей «как в GCC» и «как в MSVC», плюс немало особенностей у всяческих нишевых компиляторов. Для понимания разницы первых двух вариантов гугли -mms-bitfields и __attribute__((ms_struct)).

В runtime это достаточно просто, но не понято зачем кроме assertions:

#include <string.h>
#include <assert.h>

#ifdef _MSC_VER
#include <intrin.h>
#endif

struct foo {
 int p:9;
 int bar:10;
 int q:11;
};

unsigned get_foobar_mask() {
  assert(sizeof(foo) <= sizeof(int));
  foo xyzzy;
  memset(&xyzzy, 0, sizeof(xyzzy));
  assert(xyzzy.bar == 0);
  xyzzy.bar = -1;

  unsigned mask = 0;
  memcpy(&mask, &xyzzy, sizeof(xyzzy));
  return mask;
}

unsigned get_foobar_offset() {
 unsigned mask = get_foobar_mask();
 assert(mask != 0);
 #ifdef _MSC_VER
 unsigned long index;
 _BitScanForward(&index, mask);
 return index;
 #else
 return __builtin_ctz(mask);
 #endif
}

Можно скопипастить и поиграться на https://godbolt.org/

Deleted
()
Ответ на: комментарий от Deleted

уложено всё в pragma pack

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

например, есть структура, как в шапке, и есть какой-нибудь spinbox, который редактирует значение поля a1. тогда в виджете значения будут 0-63, которые не соответствуют значениям байта, т.к. у нас битовое поле

короче суть в том, чтобы всё само

luntik2012
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.