Please Note: This question is not a duplicate of ( One element array in struct )
The following code is excerpted from the Linux kernel source (version: 3.14)
struct files_struct
{
atomic_t count;
struct fdtable __rcu *fdt;
struct fdtable fdtab;
spinlock_t file_lock ____cacheline_aligned_in_smp;
int next_fd;
unsigned long close_on_exec_init[1];
unsigned long open_fds_init[1];
struct file __rcu * fd_array[NR_OPEN_DEFAULT];
};
I just wonder why close_on_exec_init
and open_fds_init
are defined as arrays containing one element, rather than just defined as unsigned long close_on_exec_init;
and unsigned long open_fds_init;
.
My best guess: The addresses of these fields are used much more often than their actual values. In this case, making them size-1 arrays saves typing
&
every time their address is needed, since in C using the name of an array in an expression is in nearly all cases exactly equivalent to taking the address of its first element:(As others have pointed out in the comments, it can't be that the fields are being used as a hack for variable-length arrays, since there is more than one and they don't appear at the end of the
struct
.)[EDIT: As pointed out by user3477950, an array name is not always identical to the address of its first element -- in certain contexts, like the argument to
sizeof
, they mean different things. (That's the only context I can think of for C; in C++, passing an array name as an argument can also enable a template parameter's type to be inferred to be a reference type.)]These fields are an optimization so Linux doesn't have to perform as many allocations for a typical process that has no more than
BITS_PER_LONG
open file descriptors.The
close_on_exec_init
field provides the initial storage forfdt->close_on_exec
when afiles_struct
is allocated. (Seedup_fd
infs/file.c
.)Each bit of
fdt->close_on_exec
is set if the corresponding file descriptor has the “close-on-exec” flag set. Thus Linux only needs to allocate additional space forfdt->close_on_exec
if the process has more open file descriptors than the number of bits in anunsigned long
.The
open_fds_init
field serves the same function for thefdt->open_fds
field. Thefd_array
field serves the same function for thefdt->fd
field. (Note thatfd_array
has a size ofBITS_PER_LONG
.)The
close_on_exec_init
andopen_fds_init
fields formerly had typestruct embedded_fd_set
, but were changed to bare arrays in this commit. The commit message doesn't explain why the author chose to use one-element arrays instead of bare scalars. Perhaps the author (David Howells) simply wanted to avoid using the&
operator.