Как вы преобразуете из битового поля в указатель? - PullRequest
1 голос
/ 04 января 2011

Я написал следующий фрагмент кода, который производит

предупреждение: инициализация делает указатель из целого числа без приведения

ИЛИ

предупреждение: приведение к указателю из целого числа другого размера

из gcc (GCC) 4.1.1 20070105 (Red Hat 4.1.1-52)

struct my_t {
  unsigned int a     : 1;
  unsigned int b    : 1;
};

struct my_t mine = {
  .a = 1,
  .b = 0
};

const void * bools[] = { "ItemA", mine->a, "ItemB", mine->b, 0, 0 };

int i;
for (i = 0; bools[i] != NULL; i += 2)
  fprintf(stderr, "%s = %d\n", bools[i], (unsigned int) bools[i + 1] ? "true" : "false");

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

Спасибо, Chenz

Ответы [ 4 ]

2 голосов
/ 04 января 2011

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

struct named_bool {
    const char* name;
    int         val;
};

const struct named_bool bools[] = {{ "ItemA", 1 }, { "ItemB", 1 }, { 0, 0 }};
1 голос
/ 04 января 2011
const void * bools[] = { "ItemA", mine->a, "ItemB", mine->b, 0, 0 }; 

Есть несколько проблем с этим фрагментом:

  1. mine не объявлен как тип указателя (по крайней мере, в коде, который вы опубликовали), поэтому вы не должныиспользовать оператор выбора компонента ->;
  2. Если вы измените это на оператор выбора ., вы попытаетесь сохранить логическое значение в a или b в качестве указателя, а это не то, что вам нужно;
  3. Но это не имеет значения, поскольку вы не можете взять адрес битового поля (§ 6.5.3.2, параграф 1).

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

struct checkedObject {void *objPtr; int check};

, и инициализировать массив как

struct checkedObject[] = {{"ItemA", 1}, {"ItemB", 0}, {NULL, 0}};

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

0 голосов
/ 04 января 2011

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

const void * bools[] = { "ItemA", mine->a ? &bools : 0, "ItemB", mine->b ? &bools : 0, 0, 0 };

При этом используется указатель NULL для false и ненулевой указатель (в данном случае &bools, но указатель на любой объект изправильная продолжительность хранения будет в порядке) для истины.Затем вы также удалили бы приведение к unsigned int в тесте, чтобы оно было просто:

fprintf(stderr, "%s = %d\n", bools[i], bools[i + 1] ? "true" : "false");

(нулевой указатель всегда оценивается как ложный, а ненулевой указатель как истинный).

Однако , я согласен, что вам лучше создать массив structs.

0 голосов
/ 04 января 2011

Две проблемы:

  1. Не уверен, почему вы пытаетесь конвертировать unsigned int a:1 в void*.Если вы пытаетесь сослаться на него, синтаксис будет &mine->a, а не mine->a, но ...

  2. Невозможно создать указатель на бит в C (по крайней мере, насколько я знаю).Если вы пытаетесь создать указатель на бит, вы можете рассмотреть один из следующих вариантов:

    • Создать указатель на структуру битового поля (т.е. struct my_t *), и(при необходимости) используйте отдельный номер, чтобы указать, какой бит использовать.Пример:

      struct bit_ref {
          struct my_t  *bits;
          unsigned int  a_or_b; // 0 for bits->a, 1 for bits->b
      }
      
    • Не использовать битовое поле.Используйте char для каждого флага, так как это самый маленький тип данных, на который вы можете создать указатель.

    • Используйте битовое поле, но реализуйте его вручную с логическими операциями.Пример:

      typedef unsigned int my_t;
      
      
      #define MY_T_A (1u << 0)
      #define MY_T_B (1u << 1)
      
      
      struct bit_ref {
          struct my_t  *bits;
          unsigned int  shift;
      };
      
      
      int deref(const struct bit_ref bit_ref)
      {
          return !!(bit_ref.bits & (1 << bit_ref.shift));
      }
      
...