1

Many Kernel modules seem to opt for the following struct initialization style;

struct file_operations sample_fops = {
.owner = THIS_MODULE,
.read = sample_read,
.write = sample_write,
.ioctl = sample_ioctl,
.open = sample_open,
.release = sample_release,
};

I can wrap my head around when this style is used for primitives and pointer data types but I can't figure out how they work so seamlessly for functions.

When and where are the parameters for this type of initialization created? Is it in the scope of the file or in the scope where the struct is utilized. Can you access the parameters (for instance a pointer to buffer passed as an argument to the write function) or do you have to initialize the struct in a different style in order to be able to do that?

Furthermore, if sample_fops is called multiple times, is it the same struct throughout the file? And where is it kept in the memory during its lifetime? Are the parameters kept in the same place too?

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 5
    These structs have function _pointers_. The arguments, whatever they are, are passed when called, they are unrelated to this struct. – Mat Jul 19 '19 at 12:23
  • 1
    @Mat that looks like an answer. – Yunnosch Jul 19 '19 at 12:28
  • I was asking spesifically related to linux when these tagged structs are initialized and called without explicitly naming parameters, I should have been clearer my bad – Yusuf Gürkan Bor Jul 20 '19 at 12:06

2 Answers2

2

I have not exactly understood your question but this is

struct file_operations sample_fops = {
.owner = THIS_MODULE,
.read = sample_read,
.write = sample_write,
.ioctl = sample_ioctl,
.open = sample_open,
.release = sample_release,
};

a declaration of the object sample_fops that has the type struct file_operations.

It seems that the data members of the structure are declared as pointers to functions and in this declaration function designators as for example sample_open are used to initializa corresponding data members of the structure.

Here is a demonstrative program.

#include <stdio.h>

void f( void )
{
    puts( "Hello Yusuf Gürkan Bor" );
}

struct A
{
    void ( *hello )( void );    
};

int main( void )
{
    struct A a = { .hello = f };

    a.hello();
}

The program output is

Hello Yusuf Gürkan Bor

This record in the initializarion .fp = f is called a designation initialization. It uses the name of a data member of a structure that is initialized.

In fact you can equivalently to write

struct A a = { f };

But for a such an initialization you have to keep the order of initializers relative to the order of data members.

Here is another example when a function accepts an argument.

#include <stdio.h>

void f( const char *name )
{
    printf( "Hello %s\n", name );
}

struct A
{
    void ( *hello )( const char * );    
};

int main( void )
{
    struct A a = { .hello = f };

    a.hello( "Yusuf Gürkan Bor" );
}

Its output is the same as shown above.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • Thank you, the last snippet was exactly what I was looking for. – Yusuf Gürkan Bor Jul 20 '19 at 12:07
  • BTW I was trying to figure out how linux kernel handles when those functions are not explicitly named or called, similar to the answer of [link](https://stackoverflow.com/questions/15215865/netlink-sockets-in-c-using-the-3-x-linux-kernel?lq=1) where the line of code `nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, 0, hello_nl_recv_msg,NULL,THIS_MODULE);` does not have explicitly named arguments – Yusuf Gürkan Bor Jul 20 '19 at 12:12
0

The following snippet:

int main ()
{
    typedef struct ArrayType
    {
        int field1;
        int field2;
    };

    struct ArrayType myArray =
    {
        .field1 = 0,
        .field2 = 1,
    };
}

is equivalent to

int main ()
{
    typedef struct ArrayType
    {
        int field1;
        int field2;
    };

    ArrayType myArray;
    myArray.field1 = 0;
    myArray.field2 = 1;
}

if you have a pointer to function, this can work as well.

int function1(int a,int b){ return a+b};
void function2(int c) {};

int main ()
{
    typedef struct ArrayType
    {   
        int(*function1)(int,int);
        void(*function2)(int);
    };

    ArrayType myArray;
    myArray.function1= thisFunction;
    myArray.function2= thatFunction;
}
Guillaume D
  • 2,202
  • 2
  • 10
  • 37