带方括号的 C++ 函数调用

问题描述 投票:0回答:4

考虑:

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]
是荒谬的。

c++ c++14
4个回答
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 正确拒绝此代码。


10
投票

我很惊讶没有答案提到它,但是:

问题中的代码根本不是有效的 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


5
投票

由于尚未提及:

func[3, 4, 5]
func[5]
相同 - 其中的逗号是内置的 逗号运算符 计算左侧表达式,丢弃它然后计算右侧表达式。这里没有发生函数调用,代码中的逗号不是分隔函数参数。


3
投票

是的,它是关于访问尚未定义的 func+4,导致垃圾值。所以编译器会提示你以下警告信息。

hereProgram: In function 'int main()':
Program:7: warning: pointer to a function used in arithmetic
© www.soinside.com 2019 - 2024. All rights reserved.