我目前正在关注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.
问题 - 为什么差异?为什么一个人使用或不使用&符号,而另一个似乎需要它以产生预期的输出?
函数类型(包括函数名)的表达式在大多数上下文中被隐式转换为指向函数的指针.例外情况是它是一元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,但这可能不是必需的.