Reputation: 4752
You can see what I mean when you take "str"
or &"str"[0]
and &"str"
and get identical pointers but different types.
Note: I'm on a system where string literals are not distinct.
printf("%p\n", "str");
printf("%p\n", &"str"[0]);
printf("%p\n", &"str");
// hypothetical output:
// 0xADD12E550 (ptr to char)
// 0xADD12E550 (ptr to char)
// 0xADD12E550 (ptr to arr of char)
So in theory, when I dereference &"str"
, I should be able to get the first character of the string since I am dereferencing the same pointer. Peculiarly, that's not the case, I have to dereference twice. Once to get the array, then again to get the first character constant:
// &"str" = 0xADD12E550
// *(0xADD12E550) = 0xADD12E550
// *(0xADD12E550) = 's'
// **(&"str") == 's'
Maybe then this question can also answer how this is possible:
#include <stdio.h>
void dafunk() {
printf("dadftendirekt\n");
}
main() {
void (*dafunkptr)() = dafunk;
(***************dafunkptr)();
return 0;
}
Upvotes: 1
Views: 346
Reputation: 263217
The expression "str"
is of type char[4]
. (In C++, it would be const char[4]
.)
Any expression of array type is, in most contexts, implicitly converted to a pointer to the first element of the array object. This conversion is commonly referred to as "decaying". The exceptions to this are:
sizeof
operator (sizeof "str"
yields the size of the array, not the size of a pointer).&
operator (&"str"
yields a result of type char(*)[4]
, not char*
).In these three cases, an array expression keeps its array type.
A string literal refers to an implicitly created array object with static storage duration, big enough to hold the characters of the literal plus the terminating '\0'
null character. In this case, "str"
refers to an anonymous static object of type char[4]
.
So:
printf("%p\n", "str");
"str"
is implicitly converted to a char*
value, pointing to the 's'
of "str"
.
printf("%p\n", &"str"[0]);
The "str"
in "str"[0]
decays to char*
, as above. "str"[0"
yields a char*
value, pointing to the 's'
. So "str"
and "str"[0]
are of the same type and value.
printf("%p\n", &"str");
Here, since "str"
is the operand of &
, the decay doesn't occur, so &"str"
yields the address of the anonymous char[4]
object, not the address of its first character. This expression is of type char(*)[4]
, or "pointer to array of 4 char".
The expressions &"str"[0]
and &"str"
both yield pointer values, both of which point to the same location in memory, but they're of different types.
In all three cases, the result of evaluating the expression is passed as an argument to printf
. printf
with a "%p"
format requires an argument of type void*
. In the first two cases, you're passing a char*
, and the language's requirements for char*
and void*
imply that it will work as expected. In the third case, there are no such rules for char*
vs. char(*)[4]
, so the behavior of
printf("%p\n", &"str");
is undefined.
As it happens, in most implementations all pointer types have the same size and representation, so you can get away with passing a pointer of any arbitrary type to printf
with "%p"
.
In all three cases, you could (and probably should) explicitly cast the expression to void*
, avoiding the undefined behavior:
printf("%p\n", (void*)"str");
printf("%p\n", (void*)&"str"[0]);
printf("%p\n", (void*)&"str");
The second part of your question deals with a distinct issue; it's about pointers to functions. The rules for expressions of pointer type are similar to those of array type: an expression of function type (such as a function name) is implicitly converted to a pointer to the function, except when it's the operand of sizeof
(which is illegal) or &
(which yields the address of the function). That's why applying *
or &
to a function acts like a no-op. In *func
, func
first decays to a pointer to the function, *
dereferences the pointer, and the result again decays to a pointer to the function. In &func
, the &
inhibits the decay, but it yields the same pointer to the function that func
by itself would yield.
Upvotes: 1
Reputation: 145829
The object "str"
is of type array 4 of char
.
The value of "str"
is of type pointer to char
.
The value of &"str"[0]
is of type pointer to char
.
The value of &"str"
is of type pointer to an array 4 of char
.
EDIT:
So now to access for example the first character of the string, from "str"
you have to dereference the expression once:
char s = *"str"; // or s = "str"[0]
or from the expression &"str"
you have to dereference the expression twice as its type is a pointer to an array:
char s = **&"str"; // or s = *(&"str")[0]
Upvotes: 3