Почему такая структура содержит два поля массива, содержащие только один элемент?
Обратите внимание: этот вопрос не является дубликатом (одного массива элементов в структуре)
Следующий код извлекается из источника ядра Linux (версия: 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];
};
Мне просто интересно, почему close_on_exec_init
и open_fds_init
определяются как массивы, содержащие один элемент, а не только как unsigned long close_on_exec_init;
и unsigned long open_fds_init;
.
Ответы
Ответ 1
Эти поля являются оптимизацией, поэтому Linux не должен выполнять столько распределений для типичного процесса, который имеет не более BITS_PER_LONG
дескрипторы открытых файлов.
Поле close_on_exec_init
предоставляет исходное хранилище для fdt->close_on_exec
, когда выделяется files_struct
. (См. dup_fd
в fs/file.c
.)
Каждый бит fdt->close_on_exec
устанавливается, если в соответствующем файловом дескрипторе установлен флаг "close-on-exec". Таким образом, Linux нужно выделить дополнительное пространство для fdt->close_on_exec
, если процесс имеет более открытые файловые дескрипторы, чем количество бит в unsigned long
.
Поле open_fds_init
выполняет ту же функцию для поля fdt->open_fds
. Поле fd_array
выполняет ту же функцию для поля fdt->fd
. (Обратите внимание, что fd_array
имеет размер BITS_PER_LONG
.)
Поля close_on_exec_init
и open_fds_init
ранее имели тип struct embedded_fd_set
, но были изменены на голые массивы в this commit. Сообщение фиксации не объясняет, почему автор решил использовать одноэлементные массивы вместо голых скаляров. Возможно, автор (Дэвид Хауэллс) просто хотел избежать использования оператора &
.
Ответ 2
Мое лучшее предположение: адреса этих полей используются гораздо чаще, чем их фактические значения. В этом случае создание массивов размера 1 позволяет печатать &
каждый раз, когда их адрес необходим, поскольку в C, использующем имя массива в выражении, почти во всех случаях точно эквивалентно адресу адреса его первого элемента:
int x;
int y[1];
function_that_needs_address_of_int(&x);
function_that_needs_address_of_int(y);
function_that_needs_address_of_int(&y[0]); // Identical to previous line
(Как указывали другие в комментариях, не может быть, что поля используются как хак для массивов переменной длины, так как их больше одного, и они не появляются в конце struct
.)
[EDIT: Как указано пользователем 3477950, имя массива не всегда совпадает с адресом его первого элемента - в определенных контекстах, например с аргументом sizeof
, они означают разные вещи. (Единственный контекст, который я могу представить для C; в С++, передав имя массива в качестве аргумента, также может включить тип параметра шаблона, чтобы быть ссылочным типом.) ]