Указатель NULL
- это тот, который указывает на никуда. Когда вы разыскиваете указатель p
, вы говорите «дайте мне данные в месте, хранящемся в« p ». Когда p
является нулевым указателем, местоположение, хранящееся в p
, является nowhere
, вы говорите «Дайте мне данные в месте« нигде ». Очевидно, он не может этого сделать, поэтому он выбрасывает NULL pointer exception
.
В общем, это потому, что что-то не было правильно инициализировано.
Это случайная деталь (оригинальная) реализация сокетов Berkeley. В основном, реализация использовала номер файловых дескрипторов в качестве переменной размера для некоторых временных внутренних битовых массивов. Поскольку дескрипторы Unix начинаются с нуля, наибольший дескриптор будет на один меньше, чем размер любого массива с семантикой с одним слотом на дескриптор. Следовательно, требование «наибольшее-плюс-одно». Эта настройка плюс-1 могла быть поглощена самим системным вызовом, но не была.
Древняя история, вот и все. В результате правильная интерпретация первого аргумента имеет меньшее отношение к значениям дескриптора , чем к числу из них (т. Е. Максимальное количество дескрипторов, подлежащих тестированию). См. Раздел 6.3 из Stevens et al (Это переработанная и обновленная версия классического текста Rich Stevens. Если у вас ее нет, получите ее!) [/ G6]
В большинстве ABI-ядер UNIX аргументы fd_set *
для select
на самом деле unsigned *
или unsigned long *
, которые указывают на массивы слов, содержащих биты. Первый аргумент select
сообщает ядру, насколько велики эти массивы и сколько бит должно быть проверено.
Каждое слово содержит 16 или 18 или 32 или 36 или 64 бит (в зависимости от словаризации машина); ядро будет читать nfds/wordsize
слова из пользовательского пространства, используя nfds%wordsize
младшие биты из последних слов (и всех битов других слов).
Структура данных fd_set
и связанные с ней функции были введены POSIX, чтобы иметь простой способ управления этими битами, которые также могут быть переносимыми для других систем, которые использовали некоторое другое представление и уровень ядра ABI.
Идея заключается в том, что первый параметр может использоваться функцией выбора для оптимизации времени, считывающего fd_set.
В руководстве:
man select
указано:
nfds - наименованый файловый дескриптор в любом из трех наборов, плюс 1.
blockquote>Таким образом, функция select проверяет только, что fds меньше этого в fd_set, а не все возможные fds в fd_set. Этот размер определен в константе FD_SETSIZE.
fd_set
может иметь несколько значений. Если select()
"проверяет только fds меньше этого в fd_set и не все возможные fds в fd_set", это будет пропускать значения.
– Remy Lebeau
2 July 2014 в 20:21
nfd
. Посмотрите на формулировку своего ответа, хотя: «функция select проверяет только, что fds меньше этого значения в fd_set , а не все возможные fds в fd_set ». Это означает, что значения, добавленные в fd_set, могут быть пропущены. Просто исправьте свою формулировку, чтобы было ясно, что select()
не проверяет все возможные fds, а только fds, фактически добавленные в fd_set.
– Remy Lebeau
2 July 2014 в 22:15
В системах * Nix файловые дескрипторы являются только индексами в системной таблице, а структура fd_set
содержит битовую маску, соответствующую этим индексам. Когда дескриптор добавляется к fd_set
, соответствующий бит активируется. select()
должен знать наивысшее значение дескриптора, чтобы он мог перебирать биты и знать, к какому из них нужно остановиться.
В Windows сокеты представлены дескрипторами объектов ядра, а не индексами. Структура fd_set
содержит массив дескрипторов сокетов и счетчик числа сокетов в массиве. Таким образом, select()
может просто перебирать массив, и поэтому первый параметр select()
игнорируется в Windows.