How does an array of functions recognize the position of the next element?

Asked

Viewed 105 times

8

Why do you ask:

The question may seem strange, but is that I am a beginner in programming and at this moment I am studying pointers to function and in an example in the book by which study is presented the possibility of creating pointers to function and storing them in a array, among one of its purposes would be the creation of a system controlled by a menu of options.

Code:

Note: I will not put all the code here, but only what I think is enough to elaborate the question. If the reader finds it necessary, the full example code taken from the book is at the end of the text.

First an array of function pointers of the void type is defined that take an integer type argument:

void (*f[ 3 ])( int ) = { function1, function2, function3 };

Through a prompt the user informs an integer that is stored in a variable with identifier Choice. This same variable is used in the function pointer array subscript:

(*f[ choice ])( choice );

The function contained in the position Choice of array is executed with the assignment of an integer parameter. Hence my question:

Question:

It is a very theoretical question, indeed, but I would like to understand how the compiler C recognizes the space in bytes that must travel in memory to access another function, because as far as I know, the subscript of a array in C is just an operator that adds an integer following a pointer arithmetic - If you obey that logic, in the example presented should be covered (**choices * qtd. bytes de uma função**).

C: how to program / Paul Deitel, Harvey Deitel ; -- 6. ed, 2011. p. 269.

/* Fig. 7.28: fig07_28.c
Demonstrando um array de ponteiros para funções */
#include <stdio.h>

/* protótipos */
void function1( int a );
void function2( int b );
void function3( int c );

int main( void )
{
    /* inicializa array de 3 ponteiros para funções que usam um
    argumento int e retornam void */
    void (*f[ 3 ])( int ) = { function1, function2, function3 };

    int choice; /* variável para manter escolha do usuário */

    printf( "Digite um número entre 0 e 2, 3 para sair: " );
    scanf( "%d", &choice );

    /* processa escolha do usuário */
    while ( choice >= 0 && choice < 3 ) {

        /* chama a função para o local selecionado do array f e passa
        choice como argumento */
        (*f[ choice ])( choice );

        printf( "Digite um número entre 0 e 2, 3 para terminar: ");
        scanf( “%d”, &choice );
    } /* fim do while */

    printf( "Execução do programa concluída.\n" );
    return 0; /* indica conclusão bem-sucedida */
} /* fim do main */

void function1( int a )
{
   printf( "Você digitou %d, de modo que function1 foi chamada\n\n", a );
} /* fim de function1 */

void function2( int b )
{
   printf( "Você digitou %d, de modo que function2 foi chamada\n\n", b );
} /* fim de function2 */

void function3( int c )
{
   printf( "Você digitou %d, de modo que function3 foi chamada\n\n", c );
} /* fim de function3 */
  • I’m new to Stackoverflow too, when I went to add a title I pressed ENTER hoping to add a line break, but I ended up publishing the question. So I just wanted to finish: Does the compiler really recognize the size of the function in memory? Or, in another hypothesis, what the compiler recognizes are pointers with an undefined compile-time size?

2 answers

5


It seems to me a matter of text interpretation. Read again the name of the mechanism. It is a pointer to function. So he’s a pointer, right?

Every data can have its size obtained with the operator sizeof. And in this case it is good to use it even if you know the size beforehand because it will Compile in another architecture and the size change.

You could take the size of the pointer to function, but the size of the pointer does not change according to what it is pointing, the pointer only has one size. So I think it’s safe, if you don’t have a very creative mechanism of your own, to use a sizeof(void *) to catch the size of the pointer. The void is a joker type. You can also use something like sizeof(function1).

In the overwhelming majority of cases it will be 4 or 8 bytes (most common today). There are rare cases today that can be 2 bytes and other sizes are very esoteric.

You seem to think this one array pointers have the function in it. But that’s not what happens, the pointer, by definition, is a mechanism of indirect, It points to another place, and one of its uses is to have a shape of the same size indicate things of different sizes. Maybe I’m missing an understanding of what a pointer is:

Diagrama de como o ponteiro aponta

A array it needs linearity of size, all its elements need to have its equal size. Functions (the same machine code) have different sizes, so you cannot put functions in the array, nor would it make much sense either, so the pointer is used. I imagine you understand this from pointer arithmetic.

If you pay close attention to the mechanism, functions naturally have pointers, even normal functions are always called through a pointer. When compiling does not go the name, or the body of the function (in source code or binary code), goes the relative pointer of where the function is.

So, considering a 64-bit architecture.

void (*f[ 3 ])( int ) = { function1, function2, function3 };

I put in the Github for future reference.

f is the variable with a data that has 24 bytes, so it will have the address where the executable bytes of these three functions are allocated.

For your code the function name is a symbol that internally the compiler knows is a pointer to some memory address where he will place the function. This address may change for several reasons.

The compiler can reserve the space and put the actual address only later when he knows the address the function will be.

The Linker will certainly change this value because along with other things the function address will be another.

And when performing the function will enter a location yet to be determined at that time (it will not always change the address of the function because it can be relative to a base address, depends on implementation).

In fact the exact way it works will always depend on how the compiler thought best to do it and not whether the language specification requires a specific way of doing it at some point. But the basic thing is this, you can’t do something useful so creatively.

  • 1

    I get it, it’s actually much simpler than I thought. What I have there is a pointer that contains a list of pointers, would that be something? When I put the function name in fact I’m already referring to a pointer to function. In the example, the f pointer would point to three other pointers for function: function1, function2 and function3, each in an 8 byte space (which is what I got with sizeof). Is my thinking correct? When I asked the question I was not fully aware that the function’s own name was a pointer. Thank you very much for the clarifications.

  • 2

    Quando eu coloco o nome da função na verdade eu já estou me referindo a um ponteiro para função yes. o ponteiro f apontaria pera outros três ponteiros para função yes. The function name is a symbol for an address, the name itself is not the pointer, but it has an address there that behaves like a pointer. After compiled names disappear.

2

A list of pointers for functions contains only pointers, not the "body" of the functions. And usually the function pointers have the same size as the pointers for any other object.

Nor is there an easy way to find the size of the function body from within the program (and, if there were, it would not be useful for anything).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.