All streams
Search
Write a publication
Pull to refresh
2
0

User

Send message

Нет.

У суперинтеллекта есть интересы?
Даже по поводу понимания есть сомнения.

Здесь важен второй фактор, а именно -- постоянство занятия.

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

Нет.

Программист -- это составитель управляющих программ для ЭВМ.

Зато вы -- архитектор, разработчик ТЗ, разработчик протоколов, алгоритмист, отлаживатель/тестировщик (избавлятель программ от "лажи").

Когда то да.

А сейчас?
На промежутке в 25 лет вполне имеет смысл учитывать явление фантазма.

Ваши интерпретации примечаний никого не интересуют.

Зато они интересуют тех, кто хочет понять, как всё происходит на самом деле.
Мы же в публичном поле общаемся.

Гарантий того что написано в описании возвращаемого значения примечания не дают.

Да, это проблема большинства документаций: остаются двусмысленности и не отвеченные вопросы.

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

Вообще-то, код -- не мой, если вы ещё до сих пор не заметили.

Функция есть, но не используется, а в реальности используется блокирующий ввод/вывод, и обсуждается именно он.

Однако вы не обрабатываете эту ситуацию и для случая неблокирующего вызова у вас обработка не сделана.

Для случая неблокирующего вызова обработка, очевидно, не сделана, потому что данный случай в текущем варианте кода не используется.

Ваши оценки тоже никого не интересуют.

Это, потому что вы не можете их принять.

Цель review заключается не в том, чтобы reviewer своими резкими высказываниями с намеренными недосказанностями пытался создавать ложное впечатление одновременно и собственного мнимого "величия", и мнимой ничтожности review'ируемого, а в том, чтобы объяснить проблемные места и задать направление, что следует изучить, дабы review'ируемый мог эффективно подтянуть свой уровень именно в том, что требуется для исправления проблемных мест, и в следующий раз выдавать уже код, близкий к нормальному.

Задание не выполнено.

Вы так упорно продолжаете это повторять, хотя все уже неоднократно это видели. Или вы в этом всё ещё не уверены?

А, то есть, у вас и сейчас такое же понимание?

Тогда понятно, почему вы выкладываете в качестве "примера, как надо" такой код.

char *tmp = (char*)p;

Для чего здесь приведение к (char *) ?
Или это демонстрация вашего понимания const 25-летней давности?

Однако, это -- общепринятая практика, поэтому специально об этом и не говорят.

На самом деле, сказано:

При старте сервер открывает TCP сокет с IP адресом и портом из стартовых параметров(1 и 2 параметры), берет его на прослушивание и ожидает подключений от клиента.

Написано "подключений", во множественном числе.
При этом, из описания алгоритма работы клиента ясно, что клиент открывает только одно TCP/IP-соединение.

Значит, после того, как клиент закроет соединение и завершится, сервером будет обработано только одно подключение от клиента, поэтому, раз в условии написано "подключений", сервер должен продолжить, чтобы принять ещё хотя бы одно подключение.

Также, по поводу клиента явно сказано, что он завершает работу, а по поводу сервера -- нет.

Это вы с кем сейчас спорите?

Разве это имеет хоть какое-то значение?
Авторитетов не существует.
Существуют только аргументы.

Читайте документацию по send.

Вот это -- уже совсем другое дело.

https://www.opennet.ru/docs/RUS/linux_base/node250.html

Разве там сказано, что может быть записано меньше, чем затребовано?

Функция возвращает число записанных в сокет байтов ( в нормальном случае должно быть равно значению параметра len ) или -1 в случае ошибки.

"Ненормальный" случай исчерпывающе и недвусмысленно не описан.
Можно предположить, что под "ненормальным" случаем понимается возврат -1.
Правда, не сказано, что "ненормальный" случай этим и исчерпывается.
Явно про что-то, отличное от len и -1 не сказано.

И это -- какая-то "вторичная" документация, она может быть искажённой и поэтому --ошибочной. Смотреть следует первичную.

К тому же, оказывается, что есть различия в поведении для UNIX'ов и для Windows, поэтому ссылаться на UNIX-документацию здесь не следует.

https://docs.microsoft.com/ru-RU/windows/win32/api/winsock2/nf-winsock2-send

Хорошо.

Return value

If no error occurs, send returns the total number of bytes sent, which can be less than the number requested to be sent in the len parameter. Otherwise, a value of SOCKET_ERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError.

Это -- не вся правда.
Там есть ещё кое-что:

If no buffer space is available within the transport system to hold the data to be transmitted, send will block unless the socket has been placed in nonblocking mode. On nonblocking stream oriented sockets, the number of bytes written can be between 1 and the requested length, depending on buffer availability on both the client and server computers.

Видите, в секции для return value не стали уточнять, что which can be less than the number requested to be sent in the len parameter относится к сокету, который has been placed in nonblocking mode.

В приведённом же коде сокеты не переводятся в nonblocking mode.
Поэтому там не требуется проверять, весь ли затребованный блок был отправлен.

Вам на практике удавалось создать/наблюдать ситуацию, когда для блокирующих сокетов под Windows реально возникает эффект возврата из send меньшего количества, чем затребовано?

И вообще, с таким кодом как у вас, лучше ни с кем не спорить. Просто впитывайте то что вам говорят, пока ещё без подколок и издевательств.

Почему человек должен вам верить на слово, что ему именно так и следует поступать?
Авторитетов не существует.
Или это акт -- "устрашения", учитывая упоминание подколок и издевательств?

Задание не выполнено.

Вы точно не готовы review'ить чужой код.

А при чём тут клиент? Речь идёт о сервере. Клиент можно и много раз запустить с разных хостов.

Сервер будете каждый раз перезапускать для приёма одного файла?

В задании написано -- "хранить файлы".

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

Или что сервер не должен завершаться после приёма одного файла?

Не проще ли ясно выражать свои мысли, что именно вы имеете ввиду?

Да и с параметром никаких проблем, напишите через разделитель {;,+} а не пробел.

Нет, проблема есть -- клиент тогда должен разобрать этот параметр.
Но в задании ничего такого нет.

А как вы в четвертом параметре для клиента передадите несколько имён файлов?

Но проблема с одновременностью, конечно, имеется; вот и гадай теперь, как быть…

Очень просто: скажем, каждые 3 месяца докупается один диск и меняется на один из тех, что был установлен в RAID'е с самого начала, и так -- пока не будет докуплено N - 1 дисков.

В результате, в RAID'е будут диски с "разбегом" в 3 месяца, а в запасе тоже будут диски, с частично отработанным ресурсом.

В дальнейшем, при выходе из строя дисков в RAID'е, логично будет заменять их на диски из запаса, выбирая такие из них, чтобы "разбег" по выработке ресурса дисков в RAID'е оставался относительно равномерным.

Риск того, что новые диски в самом начале массово начнут выходить из строя, невелик.
Да и никакие ухищрения при таком развитии событий не спасут.

Но чем дальше от момента создания RAID'а, тем диверсифицированнее при таком подходе становится защита от флеш-моба дискового "падежа".

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

Вы считаете const частью типа (и это правильно, потому что const можно убрать под typedef).

Буквально на каждом шагу в стандарте можно прочитать:

A pointer or reference to a cv-qualified type...

"cv-qualified type".

То, что const является частью типа, ярче всего проявляется в определении множества переменных. Так не получится определить:

int a, const b{5};

вместо:

int a;
int const b{5};

Или -- наоборот, отменить const, который указан для типа, для некоторых из переменных, определяемых через запятую.

То есть, запись

int * const p;

Я логически группирую как int * (const p);и читаю как «константный объект p, являющийся указателем на int».

Тогда, если следовать этой логике, необходимо писать:

int const i;

логически группировать как int (const i); и читать как "константный объект i, являющийся int'ом".

Наверное, ваш подход ближе к тому, как компилятор видит код.

Да, поскольку квалификаторы являются частью типа по стандарту, а компиляторы следуют стандарту.

Но лично я быстрее соображаю, когда имею дело с «константным объектом», чем с «объектом константного типа», потому что при попытке что-то сделать с p, во втором случае нужно пройти на уровень глубже и увидеть, что тип не позволяет его менять, а в первом случае я знаю, что сам объект не изменяемый.

Думаю, это вопрос перестройки мышления.

Я выбрал вариант, соответствующий стандарту, потому что, несмотря на начальные усилия, которые, возможно, придётся потратить, далее не возникает никаких нестыковок и прочих неожиданностей, и можно работать с производными типами любой сложности.

Примерно так и раскручивается: p — указатель (не константный) на указатель (константный). То есть я группирую так:
int * (const *) p;
и получаю, что p указатель на const-объект.

Но правая * относится к "p — указатель (не константный)".
Не константный, а вы её пометили как (const *).

Правильная разметка — int (* const) * p;.
p — указатель (не константный, правая *) на указатель (константный, левая *) на (не константный) int.

Внимание движется справа налево, от p к int.

Если мы запишем сначала так:

int *const *p;

Затем заведём алиас на тип:

typedef int *T;

И перепишем первое, используя второе, то автоматически получим:

T const *p;

Как можно заметить, const опять справа от того, на что он действует.

А эти модификаторы никак не связаны с описанным выше механизмом, поэтому их-то, как раз, логичнее всего "запихнуть" левее типа, чтобы не "мешались", то есть, не смешивались с механизмом задания производного типа.

А если взять пример менее тривиальный?

int *const *p;

Если "в лоб" по вашей логике, то получается, что можно менять значение int и значение p, но нельзя менять значение второй слева *.

Как устроены декларации?

Слева пишется тип, справа -- выражение.
Тип результата выражения, написанного справа, есть тип, написанный слева.

Пример:

int *p;

Каков тип выражения *p?
Это написано слева: int.

Какой должен быть тип у p, чтобы выражение *p имело тип int?
Очевидно, что -- указатель на int.

Для того, чтобы не гадать, а методично прочитать тип, необходимо идти в обратную сторону: если p разыменовывается, то это -- указатель на что-то там.

При этом cv-квалификация указывается между операцией и действием:

int *const p;

То есть, операция * применяется к p, как бы, сквозь const.
Поскольку операция разыменования -- префиксная, то внимание движется справа налево: p, потом const, потом *.

Получается: p есть const'антный указатель на ... int.

Если же написано:

int const *const p;

То читается при движении внимания справа налево так: p есть const'антный указатель на const'антный int.

Это, что касается проговаривания.
Не видно, чтобы мозг ломался.

Компилятору безразлично, «const T», или «T const», стандарт разрешает оба написания.

Верно.

Правильного, логически обоснованного ответа не существует

В том смысле, что "обязательно надо так, а не иначе" -- да, не существует.

и весь спор — чистая субъективщина.

Не совсем, есть объективные соображения за то, чтобы писать справа.

Во всех случаях, кроме рассматриваемого, const действует на то, что слева. Мозг "обучается" и привыкает к этому.

Если теперь в рассматриваемом случае поступать наоборот, растёт вероятность допустить ошибку, потому что мозгу легче действовать на автомате.

Ну, и читать легче, когда всё единообразно.

Остаются только аргументы типа «так принято» и отсылки к авторитетам.

Отсылка к авторитетам не может быть аргументом.

Попробуйте привести пример. «Производный тип» у вас — это какой? Созданный наследованием?

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

Производные типы образуются с помощью "указателей на", "массивов из", "функций, возвращающих" и, если берём C++, "указателей на member такого-то типа" и "ссылок на".

"Производность" типа можно рекурсивно "увеличивать" с некоторыми ограничениями. В частности, указатель может быть на любой производный тип, кроме ссылки, функция не может возвращать массив и функцию, массив не может состоять из функций и из ссылок, указатель на member не может быть на ссылку, ссылка тоже не может быть на ссылку.

Массивы, функции и ссылки не могут иметь собственной cv-квалификации, то есть, в частности, не могут быть const.
Таковыми могут быть только указатели и указатели на member'ы.

Поскольку оба вида указателя обозначаются символом * слева от сущности, и cv-квалификация задаётся между сущностью и *, то получается, что const всегда действует на то, что слева.

Например:

// ук-ль на ук-ль на int
int **p;
// ук-ль на ук-ль на const int
int const **p;
// ук-ль на const ук-ль на int
int *const *p;
// const ук-ль на ук-ль на int
int **const p;
// ук-ль на const ук-ль на const int
int const *const *p;
// const ук-ль на ук-ль на const int
int const **const p;
// const ук-ль на const ук-ль на int
int *const *const p;
// const ук-ль на const ук-ль на const int
int const *const *const p;

Та же самая попытка сослаться на чей-то авторитет.
Мало ли, кто что предпочитает.

В итоге, он создал язык D как эволюцию C++ и в нём разрешил обсуждаемую здесь неоднозначность, явно запретив «int const» в пользу «const int». Он то, наверное, получше нас язык чувствует?

Авторитетов не существует.

Александреску -- человек?
Значит, он тоже может ошибаться, вне зависимости от опыта?
И, значит, может иметь иррациональные предпочтения?

Пользуясь тем, что для многих он -- авторитет, и эти самые многие безоговорочно примут его точку зрения, потому что -- это же Александреску так сказал, он может "протолкнуть" не лучшие решения, но -- в пользу своих предпочтений (которые, кстати, со временем имеют свойство меняться).
Человек, потому что, здесь всё понятно.

Именно поэтому могут быть только сухие аргументы.
Никаких ссылок на авторитеты быть не может.

Кстати, вы заметили, что я в этом ответе ни на какой "авторитет" и не подумал даже пытаться ссылаться?

Язык C разрешает делать объявления новых типов внутри оператора приведения типа, внутри оператора sizeof, в объявлениях функций (типы возвращаемого значения и типы параметров)

Ещё и внутри составного литерала.

Information

Rating
Does not participate
Registered
Activity