Обычной методикой, применимой во многих случаях, является использование набора значений #define
, либо через перечисления. В данной главе API nftw()
(описанный далее) также использует флаги. Для поля f_flag
структуры struct statvfs
есть только два флага:
#define ST_RDONLY 1 /* файловая система только для чтения */
#define ST_NOSUID 2 /* setuid/setgid не разрешены */
Физически каждая именованная константа представляет различные позиции битов в значении f_flag
. Логически каждое значение представляет отдельный бит информации о состоянии; т.е. некоторый факт или условие, которое является или не является истинным для данного конкретного экземпляра struct statvfs
.
Флаги устанавливаются, проверяются и очищаются с помощью побитовых операторов С. Например, statvfs()
устанавливает эти флаги, используя побитовый оператор ИЛИ:
int statvfs(const char *path, struct statvfs *vfs) {
/* заполнить большую часть *vfs */
vfs->f_flag = 0; /* Убедиться, что начинается с нуля */
if (
vfs->f_flag |= ST_RDONLY; /* Добавить флаг ST_RDONLY */
if (
vfs->f_flag |= ST_NOSUID; /* Добавить флаг ST_NOSUID */
/* оставшаяся часть процедуры */
}
Побитовый оператор И проверяет, установлен ли флаг, а сочетание побитовых операторов И и дополнения очищает флаг:
if ((vfs.f_flag & ST_RDONLY) != 0) /* True, если флаг ST_RDONLY */
vfs.f_flag &= ~(ST_RDONLY|ST_NOSUID); /* Очистить оба флага */
Побитовые операторы отпугивают, если вы не использовали их ранее. Однако, только что показанный код примера представляет обычный стиль С. Тщательно изучите каждую операцию; возможно, нарисуйте себе несколько картин, показывающих работу этих операторов. Однажды разобравшись с ними, вы можете тренировать себя, распознавая эти операторы как
Причина использования флагов кроется в том, что они обеспечивают значительную экономию пространства данных. Одно поле unsigned long
дает возможность хранить по меньшей мере 32 отдельных бита информации. GLIBC (на момент написания) определяет 11 различных флагов для поля f_flag
.[82] Если бы вы использовали для каждого флага отдельно поле char
, это потребовало бы использования 11 байтов вместо четырех, используемых unsigned long
. Если бы у вас было 32 флага, это были бы 32 байта вместо четырёх!