Reputation: 37227
Regarding zwol's answer, I'm confused why
typedef void (*fp)(void); // any pointer-to-function type will show this effect fp c = (void *)(void *)0; // invalid conversion in both C and C++
How is the last line invalid? To me, it sounds like converting int(0)
to void*
twice, where converting a pointer to the same type should be absolutely fine, like this:
int a, *pa = (int*)&a;
// ^^^^^^ Totally OK
Upvotes: 1
Views: 160
Reputation: 140495
The thing you're asking about was a contrived example, meant to illustrate a corner case of the rules of C, and the thing that's invalid isn't the double cast, it's the assignment.
If you have any pointer-to-function type, such as
typedef void (*fp)(void);
you can initialize variables of this type with any valid null pointer constant, e.g.
fp a = 0; // canonical null pointer constant in C
fp b = (void *)0; // another common choice
fp c = '\0'; // yes, really, this is a null pointer constant
fp d = (1-1); // and so is this
But you can't initialize them with a pointer to any specific type other than fp
itself, even if that pointer is a null pointer, and even if the specific type in question is void *
.
char *x = 0;
void *y = 0;
fp e = x; // invalid: no assignment conversion from `char *` to `fp`
fp f = y; // invalid: no assignment conversion from `void *` to `fp`
The line from my old answer that you were confused by,
fp g = (void *)(void *)0;
is essentially the same as fp f = y
above. The right-hand side of both assignments is a null pointer with type void *
, but not a null pointer constant, so the assignment is invalid.
You are probably now wondering why (void *)(void *)0
isn't a null pointer constant, even though (void *)0
is a null pointer constant. This is just the way the C standard happens to be written: a null pointer constant is defined as any integer constant expression with value 0, possibly with one cast to void *
in front of it. Any extra casts and it's no longer a null pointer constant (but is still a constant expression). (Integer constant expressions cannot contain internal casts to pointer types.)
In your contrasting example
int a;
int *pa = (int *)&a;
no null pointers are involved, and no integer constant expressions either, and the cast really is 100% redundant. &a
could be a constant expression (if and only if a
has static storage duration), but it is not an integer constant expression.
Upvotes: 4