Как мгновенно проверить нулевое значение структуры, не проверяя каждый ее элемент?

Предположим, у меня есть структура byte, например:

struct one_byte
{
char b1 : 1,
     b2 : 1,   
     b3 : 1,   
     b4 : 1,   
     b5 : 1,   
     b6 : 1,   
     b7 : 1,   
     b8 : 1;   
}foo;

В некоторых случаях мне нужно проверить (foo == 0), тогда мне нужно будет выполнить восемь команд:

if(foo.b1 == 0 &&
   foo.b2 == 0 &&
   foo.b3 == 0 &&
...and so on

Есть ли какой-нибудь портативный и удобный способ, который может мгновенно проверить нулевое значение только с помощью одной команды? Я пробовал функции и шаблоны, они работают очень медленно. И я попробовал union, мой компилятор не поддерживает bit [array] ....


person Community    schedule 11.02.2013    source источник
comment
Вы можете использовать std::bitset. Однако функция не должна иметь (заметной) разницы по всем 8 операторам без вызова.   -  person chris    schedule 11.02.2013
comment
Вы можете попробовать использовать макрос, например: #define IS_ZERO(var) if(var.b1==0 && var.b2 == 0...)   -  person gerrytan    schedule 11.02.2013
comment
Моя реальная структура сложна, поэтому назначение и проверка std::bitset выполняется медленно (проверено).   -  person    schedule 11.02.2013
comment
союз   -  person Breaking not so bad    schedule 11.02.2013
comment
@gerrytan: Одна команда, а не макрос. (снова восемь команд ...)   -  person    schedule 11.02.2013
comment
memcmp на все нули?   -  person Patashu    schedule 11.02.2013
comment
@Patashu, посмотри мой комментарий для @dreamlax про memcmp   -  person borisbn    schedule 11.02.2013


Ответы (6)


Используйте union, это то, для чего он предназначен

union {
  struct {
    char b1:1,b2:1,b3:1,b4:1,b5:1,b6:1,b7:1,b8:1; 
  } bits;
  unsigned char byte;
} u;

тогда вы можете назначить напрямую байт

u.byte = 15;

или биты по отдельности

u.bits.b3 = 1;

Пример

int main() {
  u.byte = 0;
  printf("%x\n", u.byte);
  u.bits.b3 = 1;
  u.bits.b4 = 1;
  printf("%x\n", u.byte);
  return 0;
}

выведет

0
c  // 12 in decimal, since b3 and b4 are set to 1
person Breaking not so bad    schedule 11.02.2013

struct one_byte zero = { 0 };

!memcmp (&variable_1, &zero, sizeof (struct one_byte))

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

#define SET_BIT(v, n) (v) |= (1<<n)
#define CLR_BIT(v, n) (v) &= ~(1<<n)
#define GET_BIT(v, n) ((v) & ~(1<<n) == 0)

char foo;

if (foo == 0)
   so_what ();
person mikyra    schedule 11.02.2013

#include <iostream>
#include <cstring>

using namespace std;
struct one_byte{
  char b1:1;
  char b2:1;
  char b3:1;
  char b4:1;
  char b5:1; 
  char b6:1;
  char b7:1;
  char b8:1;
    }__attribute__((packed));

int main(int argc, char *argv[])
{
  one_byte b1;
  int j;
  memcpy(&j, &b1, sizeof(b1)); 
  if(j == 0) cout << "Its 0";
  else cout << "It's not 0";
  return 0;
}

как насчет вышеуказанной программы?

person Aniket Inge    schedule 11.02.2013
comment
Посмотрите мой комментарий к @dreamlax о memcmp - person borisbn; 11.02.2013

!*((unsigned char *) &foo)

Должен сделать свое дело. Обратите внимание, что я использовал оператор ! для проверки нулевого значения - если вам это не нравится, можете использовать вместо него == 0.

person aaaaaa123456789    schedule 11.02.2013

Похоже, вы хотите расслабиться и испачкаться, так что как насчет:

struct one_byte Other; // a real variable
...   
if(*(char*)&Other == '\0')
person Ron Burk    schedule 11.02.2013
comment
ааааа ... правильно: unsigned более портативен, хотя с серьезным лицом трудно сказать портативным, когда мы уже опустились до этого уровня :-) - person Ron Burk; 11.02.2013

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

if (memcmp(&foo, "\0", 1) == 0)
{
    // all zero
}

У меня нет спецификации C ++ под рукой, но в спецификации C99 6.7.2.1/13 сказано (выделено мной):

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

person dreamlax    schedule 11.02.2013
comment
memcmp - не лучшая идея из-за заполнения байтов при выравнивании. В общем, не в данном конкретном случае - person borisbn; 11.02.2013
comment
@borisbn: может быть НЕТ заполнения в начале структуры, только между членами или в конце. - person dreamlax; 11.02.2013
comment
В этом частном случае - когда вы копируете только 1 байт - мой комментарий не имеет смысла, и, конечно, не может быть байтов заполнения в начале структуры / объединения. Но в целом лучше было бы избегать memcmp. Вы согласны ? - person borisbn; 11.02.2013
comment
Вы можете сравнить с one_byte со всеми обнуленными полями, чтобы избежать проблемы, на которую указал @borisbn. - person wizzwizz4; 27.05.2017