Explanation of function pointers

I have a problem with understanding some C++ syntax combined with function pointers and function declarations, that is:

Usually when we want to declare a type of function we make something like:

typedef void(*functionPtr)(int);

and this is fine for me. From now on functionPtr is a type, that represents
pointer to the function, that returns void and takes int by a value as an argument.

We can use it as follows:

typedef void(*functionPtr)(int);

void function(int a){
    std::cout << a << std::endl;
}

int main() {

    functionPtr fun = function;
    fun(5);

    return 0;
}

And we get 5 printed on a screen.

we have got pointer to function fun, we assign some existing pointer to function – function and we execute this function by a pointer. Cool.

Now as I read in some books, function and pointer to function are treated somehow the same, so in fact after declaration of function() function everytime we say function we mean real function and pointer to function at the same type, so following compiles and every instruction gives the same result (5 printed on a screen):

int main() {

    functionPtr fun = function;
    fun(5);
    (*fun)(5);
    (*function)(5);
    function(5);

    return 0;
}

So now as long as I can imagine, that pointers to functions and functions are pretty much the same, then it’s somehow fine for me.

Then I though, if pointer to function and real function is the same, then why cannot I do following:

typedef void(functionPtr)(int); //removed *

void function(int a){
    std::cout << a << std::endl;
}

int main() {

    functionPtr fun = function;
    fun(5);

    return 0;
}

This gives me following error:

prog.cpp:12:14: warning: declaration of ‘void fun(int)’ has ‘extern’ and is initialized
functionPtr fun = function;

therefore I understood, that for some reason compiler now understands, that fun is already existing function. Then I tried following:

int main() {

    functionPtr fun;
    fun(5);

    return 0;
}

And I got linking error. I somehow understand, that as compiler now treats fun as already existing function, then due to the fact, that fun is nowhere defined, I will get linking error. Therefore I changed the name of the variable:

typedef void(functionPtr)(int);

void function(int a){
    std::cout << a << std::endl;
}

int main() {

    functionPtr function;
    function(5);

    return 0;
}

So now function in main shadows global name function, so function(5) is used from declaration functionPtr function; It works fine and prints 5 on the screen.

So now I am shocked. Why did this happen? Also misleading thing is, that when function pointer is declared like this:

typedef void(*functionPtr)(int);

i can create function of type functionPtr in following manner:

functionPtr function(int a){
    std::cout << a << std::endl;
}

whereas, when declaring something like:

typedef void(functionPtr)(int);

makes this:

functionPtr function(int a){
    std::cout << a << std::endl;
}

being interpreted by a compiler as function returning function. If this is so, why previous declaration (typedef void(functionPtr)(int);) knew, that this is a function returning void and not function returning functionPtr?

Could someone please explain what is really happening underhood for me?

I am using g++ C++ compiler with C++14 option enabled.

0

Well, it is confusing a bit.

Function type and pointer to function type are indeed two different types (no more similar than int and pointer to int). However, there is a rule, that a function type decays to pointer to function type in almost all contexts. Here decaying loosely means converted (there is a difference between type conversion and decaying, but you are probably not interested in it right now).

What is important, is that almost every time you use a function type, you end up with pointer to function type. Note the almost, however – almost every time is not always!

And you are hitting some cases when it doesn’t.

typedef void(functionPtr)(int);
functionPtr fun = function;

This code attempts to copy one function (not the pointer! the function!) to another. But of course, this is not possible – you can’t copy functions in C++. The compiler doesn’t allow this, and I can’t believe you got it compiled (you are saying you got linker errors?)

Now, this code:

typedef void(functionPtr)(int);
functionPtr function;
function(5);

function does not shadow anything. Compiler knows it is not a function pointer which can be called, and just calls your original function.

4

The most interesting of your examples is this one, reproduced here without the use of typedef:

void function(int a) { // declaration and definition of 'function'
    std::cout << a << std::endl;
}

int main() {
    void function(int); // declaration of 'function'
    function(5);
}

In most contexts in C++, the re-declaration of function in local scope would shadow the global ::function. So expecting a linker-error there makes sense – main()::function has no definition right?

Except functions are special in this regard. From a note in [basic.scope.pdel]:

Function declarations at block scope
and variable declarations with the extern specifier at block scope refer to declarations that are members of
an enclosing namespace
, but they do not introduce new names into that scope.

So that code example is exactly equivalent to:

void function(int a) { /* ... */ }
void function(int ); // just redeclaring it again, which is ok

int main() {
    function(5);
}

You can also verify this by putting the global function into some namespace, N. At this point, the local scope declaration would add a name to ::, but it wouldn’t have a definition – hence you do get a linker error.


The other interesting thing you touched on is the notion of function-to-pointer conversion, [conv.func]:

An lvalue of function type T can be converted to a prvalue of type “pointer to T”. The result is a pointer to
the function.

When you have a function call expression – if the thing you’re calling is a function type, it is first converted to a pointer-to-function. That’s why these are equivalent:

fun(5);         // OK, call function pointed to by 'fun'
(*fun)(5);      // OK, first convert *fun back to 'fun'
function(5);    // OK, first convert to pointer to 'function'
(*function)(5); // OK, unary* makes function get converted to a pointer
                // which then gets dereferenced back to function-type
                // which then gets converted back to a pointer

Let’s see your examples one by one, and what they really mean.

typedef void(functionPtr)(int);

void function(int a){
    std::cout << a << std::endl;
}

int main() {

    functionPtr fun = function;
    fun(5);

    return 0;
}

Here you are creating a typedef functionPtr for functions which take and int, and don’t return values. functionPtr is not actually a typedef for a function pointer, but of an actual function.

Then you are trying to declare a new function fun, and assign to it function. Unfortunately you cannot assign to functions, so this does not work.

int main() {

    functionPtr fun;
    fun(5);

    return 0;
}

Again, you are declaring a function fun with the signature you specified. But you don’t define it, so rightfully you fail the linking phase.

typedef void(functionPtr)(int);

void function(int a){
    std::cout << a << std::endl;
}

int main() {

    functionPtr function;
    function(5);

    return 0;
}

What happens here? You define the typedef, and in the main you write functionPtr function;. This basically is simply a prototype for the function you have already written, function. It restates that this function exists, but otherwise it does nothing. In fact, you can write:

typedef void(functionPtr)(int);

void function(int a){
    std::cout << a << std::endl;
}

int main() {

    functionPtr function;
    functionPtr function;
    functionPtr function;
    void function(int);

    function(5);

    return 0;
}

How many times you want, it won’t change a thing. The function(5) you are calling after is always the same thing.

One thing you can do in C++ is to declare the prototype of a function using such a typedef, but you cannot define it in that way.

typedef void(*functionPtr)(int);

functionPtr function(int a){
    std::cout << a << std::endl;
}

Here you are defining a function which returns a function pointer, but then you do not return it. The compiler, depending on your settings, may or may not complain. But again function is completely separated from functionPtr. You have essentially written

void (*)(int)   function(int a) {
    ...
}

The last example, the one where you have a function returning a function, is simply not allowed, because it would be meaningless.

typedef void functionPtr (int);

void function (int a){
    std::cout << a << std::endl;
}

int main() {

    functionPtr *func;
    func = function;
    func(5);
    return 0;
}

You can use it in this way, I had tested.
There really a litter tricky about this issue.

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật