Crazy Chenz
Crazy Chenz

Reputation: 13198

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

Upvotes: 1

Views: 4531

Answers (4)

caf
caf

Reputation: 239201

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.

Upvotes: 0

John Bode
John Bode

Reputation: 123558

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.

Upvotes: 1

Joey Adams
Joey Adams

Reputation: 43390

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

Upvotes: 0

Nikolai Fetissov
Nikolai Fetissov

Reputation: 84189

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

Upvotes: 2

Related Questions