When is casting between pointer types not undefined behavior in C?

sleske picture sleske · Jan 26, 2011 · Viewed 8.3k times · Source

As a newcomer to C, I'm confused about when casting a pointer is actually OK.

As I understand, you can pretty much cast any pointer type to any other type, and the compiler will let you do it. For example:

int a = 5;
int* intPtr = &a;
char* charPtr = (char*) intPtr; 

However, in general this invokes undefined behavior (though it happens to work on many platforms). This said, there seem to be some exceptions:

  • you can cast to and from void* freely (?)
  • you can cast to and from char* freely (?)

(at least I've seen it in code...).

So which casts between pointer types are not undefined behaviour in C?

Edit:

I tried looking into the C standard (section "6.3.2.3 Pointers", at http://c0x.coding-guidelines.com/6.3.2.3.html ), but didn't really understand it, apart from the bit about void*.

Edit2:

Just for clarification: I'm explicitly only asking about "normal" pointers, i.e. not about function pointers. I realize that the rules for casting function pointers are very restrictive. As I matter of fact, I've already asked about that :-): What happens if I cast a function pointer, changing the number of parameters

Answer

Oliver Charlesworth picture Oliver Charlesworth · Jan 26, 2011

Basically:

  • a T * may be freely converted to a void * and back again (where T * is not a function pointer), and you will get the original pointer.
  • a T * may be freely converted to a U * and back again (where T * and U * are not function pointers), and you will get the original pointer if the alignment requirements are the same. If not, the behaviour is undefined.
  • a function-pointer may be freely converted to any other function-pointer type and back again, and you will get the original pointer.

Note: T * (for non-function-pointers) always satisfies the alignment requirements for char *.

Important: None of these rules says anything about what happens if you convert, say, a T * to a U * and then try to dereference it. That's a whole different area of the standard.