LINUX.ORG.RU
ФорумTalks

Почему вся документация написана так всрато?

 , , ,


0

2

Сначала хотел пожаловаться на конкретную систему, но копнули глубже и выяснилось, что это общая проблема.

Windows

Вот берем, например, хвалёный MSDN (до линуксов тоже доберемся).
Рассмотрим функцию _write. Опустим чёртов момент, что они депрекейтнули write в пользу _write с тем же синтаксисом, опустим что под виндой есть суперкосяк с текстовым режимом. Опустим, что может быть установлен parameters_handle, который коллбекнется при передаче невалидных параметров. Опустим то, что сигнатура использует int и unsigned вместо ssize_t и size_t:

int _write(
   int fd,
   const void *buffer,
   unsigned int count
);

Нас интересует такой момент:

If execution is allowed to continue, the function returns -1 and errno is set to one of three values: EBADF, which means the file descriptor is invalid or the file isn't opened for writing; ENOSPC, which means there isn't enough space left on the device for the operation; or EINVAL, which means that buffer was a null pointer, or that an odd count of bytes was passed in Unicode mode.

Итого нам говорят, что:

  • Если передан невалидный fd - продолжать нельзя
  • Если на диске закончилось не хватает место - то продолжать нельзя
  • Если передан кривой буфер - то продолжать нельзя

Ну то есть функция возвращает ошибку всего в трех случаях и все они критические. Окей, а что насчет возврата числа меньше, чем передано в count? Когда такое может быть? В теории когда выполнение функции прервано сигналом или когда записалось N байт и кончилось место. Однако под windows сигналы обрабатываются специально установленным коллбеком и такой вариант отметается. А что касается диска, то:

If the actual space remaining on the disk is less than the size of the buffer the function is trying to write to the disk, _write fails and doesn't flush any of the buffer's contents to the disk

То есть она не попытается записать то, что возможно (что неимоверно тупо, поскольку между моментом проверки места и попыткой записи это самое место могло появиться). Ну то есть _write под windows никогда не вернет значение меньше count (и даже больше count не вернет, несмотря на то что в текстовом режиме запишется больше(!) байтов). Еще есть прикол с 0x17 байтом.

По итогу - нигде в документации не записано - а вернет ли когда-либо _write что-то кроме -1 или count. Если никогда не вернёт, то смысла в возвращаемом count нет. Поведение сломано, сигнатура сломана, доломайте уже контракт. Причем (якобы) существует функция write, но она объявлена устаревшей и плохой, негодной функцией.

The name is deprecated because it doesn’t follow the Standard C rules for implementation-specific names.

Linux

С чего, собственно, всё началось. Читали в качестве групповой терапии ман man 2 write. И нашли такое:

       The number of bytes written may be less than  count  if,  for  example,
       there  is  insufficient space on the underlying physical medium
       Note  that  a  successful  write() may transfer fewer than count bytes.
       Such partial writes can occur for various reasons; for example, because
       there was insufficient space on the disk device to write all of the re‐
       quested bytes

Но в конце в списке errno видим:

       ENOSPC The device containing the file referred to by fd has no room for
              the data.

Т.е. сначала нам два раза говорят, что если на диске не хватает места то запишет сколько влезет и вернет N, а в списке ошибок нам говорят, что будет выставлено -1 и установлен ENOSPC как errno.

Разгадка тут простая - если на диске есть хотя бы один байт свободного пространства - оно запишет один байт. Если там ноль - то вернет -1 + ENOSPC. Но где конкретно это написано? Почему документация превратилась в противоречащий сам себе кусок текста без этого уточнения? Поведение, кстати, полностью противоположное тому, что задано для windows.

★★★★★

Зажрались вы батенька. Тут к ентерпрайзу за сотни нефти - примеры не компилируются, вызовы не правильные, при описании аргументы могут быть перепутанны, о том что описание может не соответствовать действительности или вообще быть от другого метода я ваще молчу. А тут какие-то нюансы не указанны. Зажрались вы там 😁

vtVitus ★★★★★
()
Ответ на: комментарий от vtVitus

примеры не компилируются, вызовы не правильные

Буквально на той же странице с _write результат присваивается в unsigned и проверяется на -1

PPP328 ★★★★★
() автор топика
Ответ на: комментарий от PPP328

Буквально на той же странице с _write результат присваивается в unsigned и проверяется на -1

И что из этого следует?

wandrien ★★★
()
Ответ на: комментарий от wandrien

Что формально язык это позволяет, но это максимально тупо, потому что работает ровно на одной платформе, где есть дополнение до двойки

PPP328 ★★★★★
() автор топика

Документация не для изучения, а для сведений.

dmitry237 ★★★★★
()
Ответ на: комментарий от PPP328

Преобразование signed в unsigned всегда однозначно и определено стандартом. Оно не зависит от битового формата числа.

Сравнение unsigned и signed также однозначно и определено стандартом, так как signed конвертируется в unsigned вследствие integer promotion.

Я мог бы позлорадствовать, что это еще раз говорит о твоём неумении читать документацию. Но не буду, т.к. тема с арифметикой в Си реально сделана так, чтобы об неё мозги сломать.

wandrien ★★★
()
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от PPP328

Функция должна записать не более чем размер свободного места - это единственное, что следует из документации. Сообщить о нехватке места на диске ей ничего не запрещает.

pasquale
()

поскольку между моментом проверки места и попыткой записи это самое место могло появиться

а могло наоборот пропасть, рассчитывать на это нельзя

peregrine ★★★★★
()

Обертки «типа-позикс» на винде использовать НЕ НАДО.

Еще раз. НЕ НАДО.

Они в основном для обратной совместимости.

Они кривые. Потому что винда это не юникс система, там файловые дескрипторы это совершенно другое, там ВСЁ по-другому устроено.

Тебе нужна функция WriteFile - родного API винды.

https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile

inb4, сишную стдлибу тоже желательно не использовать, а использовать родное WinAPI. В частности это из-за локалей, интероперабельности с другими частями WinAPI, и так далее.

Нет ни одной причины вообще сишные стандартные функции, по крайней мере для ввода-вывода, использовать на винде. Кроме м.б. какого-нибудь _vsnprintf_s, если так нравится форматирование аргументов по типу printf

Софт который это делает, опенсорсный, зачастую написан как говно, либо же делает это по причине легаси(сложно портировать на WinAPI портянки позикс-говна через ifdef, хотя и нужно)

lovesan ★★★
()
Ответ на: комментарий от mittorn

Сокеты это хендлы и есть. Хендлы это умные указатели на любые объекты ядра, которыми являются в т.ч. сокеты. То что они «в сишном коде» называются не HANDLE, а SOCKET или как оно там, это вообще значения не имеет.

а «int fd» это обертка, которую для всяких криворуких красноглазых сделали в прошлом, чтобы они хоть как-то могли писать.

Но это использовать не надо, надо использовать родное API винды.

lovesan ★★★
()
Ответ на: комментарий от mittorn

а LPOVERLAPPED и IOCP всякое тебе «в кроссплатформенном коде» не мешает?

Кросплатформенный код на Си итп, это всегда #ifdef и поехали, а не вот это всё вот.

lovesan ★★★
()
Ответ на: комментарий от PPP328

Это не «виндовая функция». Это функция из майкрософтовской стандартной библиотеки Си. Причем устаревшая, и для обратной совместимости, не более.

Если я пишу на каком-нибудь там ассемблере, я могу вообще эту сишную стдлибу не использовать, а дергать WinAPI.

lovesan ★★★
()
Ответ на: комментарий от lovesan

Ну кстати да, на винде все ядерные апишки всё равно в utf16 работают, а посикса в винде нет и read/write - совместимость с dos, а не posix даже

mittorn ★★★★★
()
Ответ на: комментарий от lovesan

Так в сокетах select, который требует маленьких значения дескриптора. Разве там нет внетреннего маппинга сокет-хэндл?

mittorn ★★★★★
()
Ответ на: комментарий от lovesan

В POSIX имена другие? В <io.h> был _write с точно такой же сигнатурой.

_commit тоже из DOS, и тоже в той же dll.

Могу ошибаться, в learn.microsoft.com не указана дата появления или дополнительная информация, а под DOS я никогда не писал.

MOPKOBKA ★★★★★
()
Последнее исправление: MOPKOBKA (всего исправлений: 2)

Дядь, если читать «стандарт» POSIX (и пытаться написать свою libc соответствующую) - можно рехнуться.

А если читать «стандарт» POSIX THREADS - можно рехнуться три раза. Потом пойти смотреть реализации и навечно в нирвану уйти (хинт: ни одна реализация pthreads не совместима полностью с другой. Потому что «стандарт» настолько скуден, что каждый пляшет, как хочет. Там сплошное UB)

iSage ★★★★
()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)