1

I'm currently following along with the Big Nerd Ranch's Objective-C guide, and one of the examples is as follows:

int main(int argc, const char * argv[])
{
    int i = 17;
    printf("i stores its value at %p\n", &i); return 0;
}

// output => i stores its value at 0xbffff738

int main(int argc, const char * argv[])
{
    int i = 17;
    printf("i stores its value at %p\n", &i); 
    printf("this function starts at %p\n", main); return 0;
}

// output => i stores its value at 0xbffff738
//           this function starts at 0x100000ed0

I tried using the "&" symbol in front of main, and I get the same result- 0x100000ed0. But when I remove the ampersand from in front of "i", I see only 0x11 instead of 0xbffff738.

Question- why the difference? And why does one work with or without an ampersand, while the other seems to require it in order to produce the expected output?

Richie Thomas
  • 3,073
  • 4
  • 32
  • 55
  • it's confusing, why you need to ask a c question when reading about objective c? – Jason Hu Dec 23 '14 at 21:29
  • @HuStmpHrrr: Objective C is very nearly a backward compatible superset of C, and the code in the question uses no Objective C specific features. – Keith Thompson Dec 23 '14 at 21:32
  • A variable is a symbol that represents some value at some memory address. You might want to get/set the value, and you might want to get the address. Hence, you need two different "syntaxes" (i.e., with `&` and without `&`). A function is a symbol that represents a memory address only (where the code of the function begins). So you only need one "syntax". By the way, a statically-allocated array is also a symbol that represents a memory address only, so you only need one "syntax" for that as well (with or without `&` is the same). – barak manos Dec 23 '14 at 21:32

4 Answers4

5

An expression of function type (including a function name) is implicitly converted to a pointer to the function in most contexts. The exceptions are when it's the argument to a unary sizeof or & operator. sizeof function_name is illegal, but in &function_name the subexpression function_name is not converted to a pointer; the & operator then yields the function's address.

So given that foo is the name of a function, these expressions:

foo
&foo
*foo
**foo
***foo
...

all yield the address of the function.

There are similar rules for array expressions, which are usually converted to the address of the array's first element. There's one additional exception (a string literal used in an initializer for an array object), and &array_name is valid (it yields the address of the array object, which refers to the same address but has a different type than the address of the first element).

Incidentally, the %p format expects an argument of type void*. On many systems, all pointers have the same representation, so you can probably get away with passing any pointer value -- but there's no guarantee that it will work. For maximum safety and portability, you should print a pointer value by casting it to void*:

printf("i stores its value at %p\n", (void*)&i);

And there is no standard format for printing a function pointer value. This:

printf("this function starts at %p\n", (void*)main);

is likely to work, but strictly speaking the behavior of the conversion from int (*)(int, char **) (the type of the address of main) to void* is undefined. See this question for more information.

For 100% portability, you can extract the representation of a function pointer by treating it as an array of unsigned char, but it's probably not necessary.

Community
  • 1
  • 1
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
2

In C, like array names which are converted to pointers to array's first element when passed to a function, function names are converted to the pointer to that function. In case of

printf("i stores its value at %p\n", (void *)&i);   

i is not a pointer type and hence you need to pass a pointer type argument and this would be done by placing & before i in the argument.

haccks
  • 104,019
  • 25
  • 176
  • 264
  • I'd say function identifiers **are** the address. You need the function call operator `()` to act on a function address to call it. – Jens Dec 23 '14 at 21:34
  • @Jens from type tree's point of view, function identifiers are not address. let say `typedef int (*foo)(); foo abc;`. according to this type definition, you need to invoke `abc` as `(*abc)()`, but `abc()` would work too. apparently function identifiers get handled specially. it's basically nonsense to say the meaning of function identifier, since it's just a symbol for linking. – Jason Hu Dec 23 '14 at 21:38
  • wild guess. `%p` wants object pointer but `main` is function pointer. it's undefined cast. and `&i` will autocast to `void *`. – Jason Hu Dec 23 '14 at 21:43
  • @HuStmpHrrr: The cast is a constraint violation, but my understanding is, that if compilation succeeds, it has defined semantics. POSIX appears to require that cast to work and the version not violating a constraint (which definitely is defined if all pointers share representation requirements, what POSIX mandates) is not looking that attractive: `(union { int (*f)(int, char **); void *p; }){ .f = main }.p` ... But yes, might have been the downvote reason. – mafso Dec 23 '14 at 21:59
  • @HuStmpHrrr; Today a mystery is reveled. Thanks for letting me know. I searched the standard and all over the Google but didn't find any idea how to print an address of a function. – haccks Dec 23 '14 at 21:59
  • @haccks the standard states function pointer and object pointer separately, it's really hard to say what's the standard way to do it. all i found is `Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined.` but it's ambiguous. – Jason Hu Dec 23 '14 at 22:17
  • @haccks yep. but still, it's implementation defined so it's not necessary to reveal the true address in the memory. – Jason Hu Dec 23 '14 at 22:25
2

i is not a pointer type but an integer type. You need the & operator to get its address.

main is a function designator and in an expression is converted to a pointer to a function in the usual conversion rules.

 printf("this function starts at %p\n", &main); // OK, & yields a pointer to main
 printf("this function starts at %p\n", main);  // OK also, usual conversion rules
                                                // yields a pointer to main

Note that the printf call is technically undefined behavior as p conversion specifier requires an argument of type void *.

ouah
  • 142,963
  • 15
  • 272
  • 331
  • 1
    That's undefined behavior, since %p requires a ptr-to-void. Function pointers may not be cast to object pointers without possible loss, so the best way to print a function address is casting to the widest integral type and print that. – Jens Dec 23 '14 at 21:33
  • @MattMcNabb What about casting them to the widest integral type, as I suggested? – Jens Dec 23 '14 at 22:08
  • @Jens C says for pointer to integer conversions that *"The result need not be in the range of values of any integer type".* – ouah Dec 23 '14 at 22:10
  • @Jens didn't see that bit for some reason! So `uintmax_t` then. – M.M Dec 23 '14 at 22:19
1

in C, function name is handled specially. you can see three of these give the same output:

main

*main 

&main

http://ideone.com/jMz0W4

unlike data identifiers, which have type tree system, function identifiers have no.

Jason Hu
  • 6,239
  • 1
  • 20
  • 41