Search code examples
cstringuint32uint32-t

Getting the value of a C 4-byte string as a uint


Briefly, my problem is: I'm building a dynamic memory manager, which contains various different kinds of objects. I'm marking each different kind of object with a tag, and, to make memory debugging easier, I want those tags to appear in memory as four-byte strings of stuff I can read. However, to efficiently switch on those values, I also want to consider them as unsigned 32 bit integers.

Currently the definition of the objects looks like this:

/**
 * an object in cons space.
 */
struct cons_space_object {
  char tag[TAGLENGTH];         /* the tag (type) of this cell */
  uint32_t count;              /* the count of the number of references to this cell */
  struct cons_pointer access;  /* cons pointer to the access control list of this cell */
  union {
    /* if tag == CONSTAG */
    struct cons_payload cons;
    /* if tag == FREETAG */
    struct free_payload free;
    /* if tag == INTEGERTAG */
    struct integer_payload integer;
    /* if tag == NILTAG; we'll treat the special cell NIL as just a cons */
    struct cons_payload nil;
    /* if tag == REALTAG */
    struct real_payload real;
    /* if tag == STRINGTAG */
    struct string_payload string;
    /* if tag == TRUETAG; we'll treat the special cell T as just a cons */
    struct cons_payload t;
  } payload;
};

Tags are four character string constants, e.g.:

#define CONSTAG  "CONS"

What I want to be able to so is something like

switch ( cell.tag) {
  case CONSTAG : dosomethingwithacons( cell);
  break;

But of course you can't switch on a string. However, as these are four byte strings, they could be read in memory as 32 bit unsigned ints. What I want is a macro which, given a string as argument, returns an unsigned int. I've tried

/**
 * a macro to convert a tag into a number
 */
#define tag2uint(tag) ((uint32_t)*tag)

but what it in fact does is return as a number the ASCII value of the first character at that address - that is,

tag2uint("FREE") => 70

which is the ascii code for 'F'.

Anyone solve this for me? It's twenty years since I wrote anything serious in C.


Solution

  • #define tag2uint(tag) ((uint32_t)*tag)
    

    means "dereference tag (get 'F' in your example), then convert it to uint32_t."

    What you want to do should be

    #define tag2uint(tag) (*(uint32_t*)tag)
    

    this means "treat tag as pointer to uint32_t, then dereference it."