Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ function call with square parenthesis

Tags:

c++

c++14

int func(int n)
{return n;}

int main()
{ cout << func[4] ;
cout << func[4,3,5] ;}

what do these actually mean? I guess it is about accessing func+4 and func is allocated space on calling func[4]. But, func[4,3,5] is just absurd.

like image 900
Sandeep Pal Avatar asked Oct 08 '18 06:10

Sandeep Pal


People also ask

What does square brackets mean in C?

Square brackets are used to index (access) elements in arrays and also Strings.

What does square brackets mean in syntax?

mvBASIC Syntax NotationsAnything shown enclosed within square brackets is optional unless indicated otherwise. The square brackets themselves are not typed unless they are shown in bold. | A vertical bar that separates two or more elements indicates that any one of the elements can be typed.

Can we call a function without parentheses in C?

C++ does not give compiler error if you try to call a function without parentheses. Actually it is wrong to say calling a function if we are not using parentheses , () ,with a function. This is the code for implementing stack in C++.


3 Answers

The reason this code compiles and func[4] is not a syntax error is:

1.Function types can implicitly convert to pointers of the same type. So, if we have code like this:

int f(int);

using func_t = int(*)(int);

void g(func_t);

we can write

g(f)

and aren't forced to write g(&f). The &, taking us from type int(int) to int(*)(int) happens implicitly.

2.In C (and necessarily in C++ for compatibility) pointers are connected to arrays, and when p is a pointer p[x] is the same as *(p + x). So func[4] is the same as *(func + 4).

3.*(p+x) has the type of a function int(int), but again can implicitly decay to a pointer type whenever necessary. So *(func + 4) can implicitly just be (func + 4).

4.Pointers of any type are streamable to std::cout.


Note, that just because it isn't a syntax error doesn't mean it is valid. Of course it is undefined behavior, and as the compiler warning emitted by gcc and clang indicates, pointer arithmetic with a function pointer is generally wrong, because you cannot make an array of functions. The implementation places functions however it likes. (You can make an array of function pointers but that is something else entirely.)


Edit: I should correct myself -- this answer is not entirely correct. func[4] is not valid, because the pointer is not a pointer to an object type. @holyblackcat answer is correct, see his answer for reference in the standard.

This code should be ill-formed, and gcc only compiles it without an error because they are using a nonstandard extension by default. Clang and msvc correctly reject this code.

like image 199
Chris Beck Avatar answered Oct 31 '22 23:10

Chris Beck


I'm surprised no answer mentions it, but:

The code in the question is simply not valid C++.

It's rejected by Clang and MSVC with no flags. GCC rejects it with -pedantic-errors.

a[b] (in absence of operator overloading) is defined as *(a + b), and the builtin operator + requires the pointer operand to be a pointer to an object type (which functions pointers are not).

[expr.add]/1

...either both operands shall have arithmetic or unscoped enumeration type, or one operand shall be a pointer to a completely-defined object type and the other shall have integral or unscoped enumeration type.

(Emphasis mine.)


GCC compiles the code because an extension allowing arithmetic on function pointer is enabled by default.

Due to function-to-pointer decay, func[4] is treated as &(&func)[4], which effectively means &func + 4, which (as the link explains) simply adds 4 to the numerical value of the pointer. Calling resulting pointer will most likely cause a crash or unpredicatble results.

std::cout doesn't have an overload of << suitable for printing function pointers, and the best suitable overload the compiler is able to find is the one for printing bools. The pointer gets converted to bool, and since it's non-null, it becomes true, which is then printed as 1.

Lastly, func[4,3,5] has the same effect as func[5], since in this context , is treated as an operator, and x , y is equal to y.

like image 31
HolyBlackCat Avatar answered Oct 31 '22 23:10

HolyBlackCat


Since it has not been mentioned yet: func[3, 4, 5] is identical to func[5] - the commas in there are the builtin comma operator which evaluates the left hand side expression, discards it and then evaluates the right hand side expression. There is no function call happening here and the commas in the code are not delimiting function parameters.

like image 5
Max Langhof Avatar answered Oct 31 '22 22:10

Max Langhof