开发者

How do you cast from a bit-field to a pointer?

I've written the following bit of code that is producing a

warning: initialization makes pointer from integer without a cast

OR A

warning: cast to pointer from integer of different size

from 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");

How do I get the warning to go away? No matter what I've tried casting, a warning seems to always appears.

Thanks, Chenz


Hmm, why do you insist on using pointers as booleans? How about this alternative?

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

const struct named_bool bools[] = {{ "ItemA", 1 }, { "ItemB", 1 }, { 0, 0 }};


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

There are several problems with this snippet:

  1. mine isn't declared as a pointer type (at least not in the code you posted), so you shouldn't be using the -> component selection operator;
  2. If you change that to use the . selection operator, you'd be attempting to store the boolean value in a or b as a pointer, which isn't what you want;
  3. But that doesn't matter, since you cannot take the address of a bit-field (§ 6.5.3.2, paragraph 1).

If you're trying to associate a boolean value with another object, you'd be better off declaring a type like

struct checkedObject {void *objPtr; int check};

and initialize an array as

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

Bit-fields have their uses, but this isn't one of them. You're really not saving any space in this case, since at least one complete addressable unit of storage (byte, word, whatever) needs to be allocated to hold the two bitfields.


Two problems:

  1. Not sure why you are trying to convert unsigned int a:1 to a void*. If you are trying to reference it, the syntax would be &mine->a rather than mine->a, but...

  2. You can't create a pointer to a bit in C (at least as far as I know). If you're trying to create a pointer to a bit, you may want to consider one the following options:

    • Create a pointer to the bitfield structure (i.e. struct my_t *), and (if necessary) use a separate number to indicate which bit to use. Example:

      struct bit_ref {
          struct my_t  *bits;
          unsigned int  a_or_b; // 0 for bits->a, 1 for bits->b
      }
      
    • Don't use a bit field. Use char for each flag, as it is the smallest data type that you can create a pointer to.

    • Do use a bit field, but implement it manually with boolean operations. Example:

      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));
      }
      


There's a few ways you could get rid of the warning, but still use a pointer value as a boolean. For example, you could do this:

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

This uses a NULL pointer for false, and a non-null pointer (in this case, &bools, but a pointer to any object of the right storage duration would be fine) for true. You would also then remove the cast to unsigned int in the test, so that it is just:

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

(A null pointer always evaluates as false, and a non-null pointer as true).

However, I do agree that you are better off creating an array of structs instead.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜