I think this question is more about C than the Linux kernel.
Members of structure or union types cannot have function type, but they can have pointer to function type. For example, in the Linux kernel, the open
member of struct file_operations
needs to be declared with a pointer to function type: int (*open)(struct inode *, struct file *);
. Declaring the member as int open(struct inode *, struct file *);
is an error.
In this variable definition in Linux kernel code:
static struct file_operations fops =
{
.open = dev_open,
.read = dev_read,
.write = dev_write,
.release = dev_release,
};
Incidentally, the above should normally have the owner
member initialized like so:
.owner = THIS_MODULE,
The expressions dev_open
, dev_read
, dev_write
and dev_release
are function designators being used as assignment expressions to initialize the members of fops
. A function designator is an expression that has function type. Unless it is the operand of sizeof
, _Alignof
, or the unary &
operator, a function designator is converted to a pointer to function type. Therefore, the above definition of variable foo
is exactly equivalent to:
static struct file_operations fops =
{
.open = &dev_open,
.read = &dev_read,
.write = &dev_write,
.release = &dev_release,
};
(Don't forget to also initialize .owner = THIS_MODULE,
.)
There, the function designators are operands of the unary &
operator and so are not converted to pointer to function types implicitly, but the &
operator is converting them to pointer to function types explicitly.
After the above initialization of fops
, rc = fops.open(inode, file);
indirectly calls dev_open(inode, file)
and assigns the return value to rc
. You may sometimes see this written in an older style: rc = (*fops.open)(inode, file);
. They both do the same thing. The operand of the function call operator (
)
is in fact always a pointer to a function. In the case of rc = (*fops.open)(inode, file);
, fops.open
has a pointer to a function type. (*fops.open)
dereferences fops.open
to a function type but since (*fops.open)
is a function designator it is implicitly converted back to a pointer to function type before the function call. Similarly, in the direct call rc = dev_open(inode, file);
, dev_open
is a function designator and so has a function type, but is implicitly converted to a pointer to function type before the function call.