为什么使用&符号来检索整数的内存地址,而不是函数的地址?

Ric*_*mas 1 c

我目前正在关注Big Nerd Ranch的Objective-C指南,其中一个例子如下:

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
Run Code Online (Sandbox Code Playgroud)

我尝试在main前面使用"&"符号,我得到相同的结果 - 0x100000ed0.但是当我从"i"前面删除&符时,我只看到0x11而不是0xbffff738.

问题 - 为什么差异?为什么一个人使用或不使用&符号,而另一个似乎需要它以产生预期的输出?

Kei*_*son 5

函数类型(包括函数名)的表达式在大多数上下文中被隐式转换为指向函数的指针.例外情况是它是一元sizeof&算子的论证.sizeof function_name是非法的,但在&function_name子表达式function_name没有转换为指针; 该&运营商则得到函数的地址.

所以这foo是函数的名称,这些表达式:

foo
&foo
*foo
**foo
***foo
...
Run Code Online (Sandbox Code Playgroud)

都产生函数的地址.

数组表达式有类似的规则,通常转换为数组第一个元素的地址.还有一个例外(在数组对象的初始值设定项中使用的字符串文字),并且&array_name是有效的(它产生数组对象的地址,它引用相同的地址,但其类型与第一个元素的地址不同) .

顺便提一下,%p格式需要一个类型的参数void*.在许多系统中,所有的指针都具有相同的表示,这样你就可以很可能逃脱传递任何指针值-但有没有保证,它会工作.为了最大限度地提高安全性和可移植性,您应该通过将指针值强制转换为void*:

printf("i stores its value at %p\n", (void*)&i);
Run Code Online (Sandbox Code Playgroud)

并且没有用于打印函数指针值的标准格式.这个:

printf("this function starts at %p\n", (void*)main);
Run Code Online (Sandbox Code Playgroud)

可能会起作用,但严格来说,转换的行为int (*)(int, char **)(地址的类型main)void*是未定义的.有关更多信息,请参阅此问题.

对于100%可移植性,您可以通过将其视为数组来提取函数指针的表示unsigned char,但这可能不是必需的.