Cody Cody - 1 month ago 9
C Question

Behavior when casting with an extra reference and dereference

Recently I asked this question about a library I am working with. I originally asked the question about a specific example, why there was code like

unsigned char *str2 = *(unsigned char **) &str;
instead of having just
unsigned char *str2 = (unsigned char*) str;
, and the answer explained the details of it in the context of
char
to
unsigned char
.

However, in the comments below that question, I was asked for more examples, so I was able to provide a few from the source using other types:

void *q = *(void **)(&p[i]);


fz_colorspace **out_colorspace = (fz_colorspace **)(void *)(&node_ptr[colorspace_off]);


(There are others that I'm having trouble finding right now, and my regex search skills are weak. I remember the basic form but can't find a line number, but that can be supplied if someone wants it.)

A comment below my question told me the behavior was going to be different for those types than it was for
char*
->
unsigned char*
, however when I tried to follow up in chat to clarify why that would be, I never received a reply.

In what ways does casting in this manner (
type2 *b = *(type2**) &a
) differ from the easier approach (
type2 *b = (type2*) a
) in the general case?
Or, does this only matter on a type by type basis?

Answer

(type2*) a evaluates a in whatever type it is and then casts the result to type2*.

*(type2**)&a takes the address of a and reinterprets that address to be one of type type2** and then dereferences it. So assuming that the pointer cast goes well, this interprets the bit pattern of a to be the bit pattern of a pointer to type2.

All of this is weird stuff, and the latter definitively has undefined behavior. Since &a is not of character type, the effecive type rule says that you may not access this object through a different type than its effective type. So derefferencing this pointer is erroneous.