C 为什么要使用&;用于检索整数的符号';s内存地址,但不是函数';谁的地址?
我目前正在跟随Big Nerd Ranch的Objective-C指南,其中一个例子如下:C 为什么要使用&;用于检索整数的符号';s内存地址,但不是函数';谁的地址?,c,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 * a
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
我尝试在main前面使用“&”符号,得到了相同的结果-0x10000ed0。但是当我从“I”前面移除“and”时,我只看到0x11而不是0xbffff738
问题-为什么不同?为什么一个使用或不使用符号,而另一个似乎需要符号才能产生预期的输出?在C中,就像数组名在传递给函数时被转换为指向数组第一个元素的指针一样,函数名被转换为指向该函数的指针。万一
printf("i stores its value at %p\n", (void *)&i);
i
不是指针类型,因此您需要传递指针类型参数,这可以通过将&
放在参数i
之前来完成。在C中,就像数组名在传递给函数时转换为指向数组第一个元素的指针一样,函数名将转换为指向该函数的指针。万一
printf("i stores its value at %p\n", (void *)&i);
i
不是指针类型,因此需要传递指针类型参数,这可以通过将&
放在参数中的i
之前来完成。i
不是指针类型,而是整数类型。您需要&
操作符来获取其地址
main
是一个函数指示符,在表达式中,它被转换为指向常用转换规则中函数的指针
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
请注意,
printf
调用在技术上是未定义的行为,因为p
转换说明符需要类型为void*
i
的参数不是指针类型,而是整数类型。您需要&
操作符来获取其地址
main
是一个函数指示符,在表达式中,它被转换为指向常用转换规则中函数的指针
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
请注意,
printf
调用在技术上是未定义的行为,因为在大多数上下文中,p
转换说明符需要类型为void*
的参数,函数类型的表达式(包括函数名)隐式转换为指向函数的指针。例外情况是当它是一元sizeof
或&
运算符的参数时sizeof function_name
非法,但在和function_name
中,子表达式function_name
未转换为指针;然后,&
运算符生成函数的地址
因此,假设foo
是一个函数的名称,则以下表达式:
foo
&foo
*foo
**foo
***foo
...
所有这些都会产生函数的地址
数组表达式也有类似的规则,通常会转换为数组第一个元素的地址。还有一个例外(数组对象的初始值设定项中使用的字符串文字),&array\u name
是有效的(它生成数组对象的地址,该地址引用相同的地址,但与第一个元素的地址具有不同的类型)
顺便提一下,%p
格式需要类型为void*
的参数。在许多系统上,所有指针都有相同的表示形式,因此您可能不需要传递任何指针值,但无法保证它会工作。为了最大限度地提高安全性和可移植性,您应该通过将指针值强制转换到void*
:
printf("i stores its value at %p\n", (void*)&i);
并且没有打印函数指针值的标准格式。这:
printf("this function starts at %p\n", (void*)main);
很可能有效,但严格来说,从int(*)(int,char**)
(主main
的地址类型)到void*
的转换行为尚未定义。有关更多信息,请参阅
为了实现100%的可移植性,您可以通过将函数指针视为
无符号字符数组来提取其表示形式,但这可能不是必需的。在大多数上下文中,函数类型的表达式(包括函数名)会隐式转换为指向函数的指针。例外情况是当它是一元sizeof
或&
运算符的参数时sizeof function_name
非法,但在和function_name
中,子表达式function_name
未转换为指针;然后,&
运算符生成函数的地址
因此,假设foo
是一个函数的名称,则以下表达式:
foo
&foo
*foo
**foo
***foo
...
所有这些都会产生函数的地址
数组表达式也有类似的规则,通常会转换为数组第一个元素的地址。还有一个例外(数组对象的初始值设定项中使用的字符串文字),&array\u name
是有效的(它生成数组对象的地址,该地址引用相同的地址,但与第一个元素的地址具有不同的类型)
顺便提一下,%p
格式需要类型为void*
的参数。在许多系统上,所有指针都有相同的表示形式,因此您可能不需要传递任何指针值,但无法保证它会工作。为了最大限度地提高安全性和可移植性,您应该通过将指针值强制转换到void*
:
printf("i stores its value at %p\n", (void*)&i);
并且没有打印函数指针值的标准格式。这:
printf("this function starts at %p\n", (void*)main);
很可能有效,但严格来说,从int(*)(int,char**)
(主main
的地址类型)到void*
的转换行为尚未定义。有关更多信息,请参阅
为了实现100%的可移植性,您可以通过将函数指针视为无符号字符数组来提取其表示形式,但这可能不是必需的。在C中,函数名是专门处理的。您可以看到其中三个提供相同的输出:
main
*main
&main
联合国