考虑:
int func(int n)
{
return n;
}
int main()
{
cout << func[4];
cout << func[4, 3, 5];
}
这些到底是什么意思?我想这是关于访问
func+4
和func
在调用func[4]
时分配的空间。
但是,
func[4, 3, 5]
是荒谬的。
此代码编译并且
func[4]
不是语法错误的原因是:
1.函数类型可以隐式转换为相同类型的指针。 所以,如果我们有这样的代码:
int f(int);
using func_t = int(*)(int);
void g(func_t);
我们可以写
g(f)
并且不被迫写
g(&f)
。 &
,将我们从类型int(int)
带到int(*)(int)
隐式发生。
2.在C中(为了兼容,在C++中必然如此)指针连接到数组,当
p
是指针时,p[x]
与*(p + x)
相同。所以func[4]
与*(func + 4)
相同。
3.
*(p+x)
具有函数类型 int(int)
,但同样可以在必要时隐式衰减为指针类型。所以 *(func + 4)
可以隐含地只是 (func + 4)
.
4.任何类型的指针都可以流式传输到
std::cout
.
注意,仅仅因为它不是语法错误并不意味着它是有效的。当然这是未定义的行为,正如 gcc 和 clang 发出的编译器警告所表明的那样,函数指针的指针算法通常是错误的,因为你不能创建一个函数数组。该实现随心所欲地放置函数。 (你可以制作一个函数指针数组,但这完全是另外一回事。)
编辑:我应该纠正自己——这个答案并不完全正确。
func[4]
无效,因为指针不是指向对象类型的指针。 @holyblackcat 答案是正确的,在标准中查看他的答案以供参考。
这段代码应该是错误格式的,gcc 只能在没有错误的情况下编译它,因为默认情况下它们使用的是非标准扩展。 Clang 和 msvc 正确拒绝此代码。
我很惊讶没有答案提到它,但是:
问题中的代码根本不是有效的 C++。
它被 Clang 和 MSVC rejected 没有标志。 GCC 以
-pedantic-errors
拒绝它。
a[b]
(在没有运算符重载的情况下)定义为 *(a + b)
,内置运算符 +
要求指针操作数是指向 object 类型(函数指针不是)的指针。
[expr.add]/1
...两个操作数都应具有算术或无作用域枚举类型,或一个操作数应为指向完全定义的对象类型的指针,另一个应具有整数或无作用域枚举类型。
(强调我的。)
GCC 编译代码,因为 默认启用允许对函数指针进行算术运算的扩展。
由于函数到指针的衰减,
func[4]
被视为 &(&func)[4]
,这实际上意味着 &func + 4
,它(如链接所解释的那样)只是将 4
添加到指针的数值中。调用结果指针很可能会导致崩溃或不可预测的结果。
std::cout
没有适合打印函数指针的 <<
重载,编译器能够找到的最合适的重载是用于打印 bool
的重载。指针被转换为bool
,并且由于它是非空的,所以它变成了true
,然后打印为1
.
最后,
func[4,3,5]
与func[5]
具有相同的效果,因为在这种情况下,,
被视为运算符,而x , y
等于y
。
是的,它是关于访问尚未定义的 func+4,导致垃圾值。所以编译器会提示你以下警告信息。
hereProgram: In function 'int main()':
Program:7: warning: pointer to a function used in arithmetic