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]只是荒谬的。
答案 0 :(得分:15)
此代码编译且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正确拒绝了此代码。
答案 1 :(得分:10)
我很惊讶没有任何提及,但是:
问题中的代码根本不是有效的C ++。
它是Clang和MSVC的rejected,没有标志。 GCC用-pedantic-errors
拒绝了它。
a[b]
(在没有操作符重载的情况下)被定义为*(a + b)
,而内置操作符+
要求指针操作数是指向对象类型的指针(不是函数指针)。
[expr.add]/1
...两个操作数都应具有算术或非范围枚举类型,或者一个操作数应是指向完全定义的对象类型的指针,而另一个操作数应具有整数或非范围枚举类型。 / p>
(强调我的。)
GCC编译代码,因为默认情况下启用了an extension allowing arithmetic on function pointer。
由于函数到指针的衰减,func[4]
被视为&(&func)[4]
,实际上是指&func + 4
,它(如链接所述)仅将4
添加到指针的数值。调用结果指针很可能会导致崩溃或结果异常。
std::cout
没有适合打印函数指针的<<
重载,并且编译器能够找到的最适合的重载是打印bool
的重载。指针将转换为bool
,由于它不是空值,因此变为true
,然后将其打印为1
。
最后,func[4,3,5]
与func[5]
具有相同的效果,因为在这种情况下,
被视为运算符,并且x , y
等于y
答案 2 :(得分:4)
由于尚未提及它:func[3, 4, 5]
与func[5]
相同-内置的逗号comma operator用于评估左侧表达式,将其舍弃然后求值右边的表情。这里没有发生函数调用,并且代码中的逗号不是分隔函数参数的地方。
答案 3 :(得分:3)
是的,它是关于访问尚未定义的func + 4并导致出现垃圾值的。因此,编译器将向您显示以下警告消息。
hereProgram: In function 'int main()':
Program:7: warning: pointer to a function used in arithmetic