Загвоздка в том, что fd_set на самом деле не «набор» в вашем мышлении. Закулисная деталь заключается в том, что реализация fd_set - это просто целое число, которое используется как битовое поле. Другими словами, выполнение
fd_set foo;
FD_CLEAR(&foo);
FD_SET(&foo, 3);
Устанавливает foo в десятичное значение 8 - устанавливает четвертый младший бит в 1 (помните, что 0 является допустимым дескриптором).
FD_SET(&foo, 3);
эквивалентно
foo |= (1 << 3);
Таким образом, чтобы выбор работал правильно, он должен знать, какие биты fd_set являются битами, которые вас интересуют. В противном случае не было бы никакого способа сообщить нулевому биту, который находится «в» наборе, но установлен в false из нулевого бита, который «не в» наборе.
В вашем примере набор fd_set с 4, 8 и 9 установленным и n = 10 интерпретируется как "Набор с 10 записями (fds 0-9). Записи 4, 8 и 9 являются истинными (следите за ними) . Записи 1, 2, 3, 5, 6, 7 являются ложными (не отслеживайте их). Любое значение fd, превышающее 9, просто не находится в установленном периоде. "