С моей точки зрения это глупость. Код надо писать так, чтобы его нельзя было записать неправильно хоть в строчку, хоть столбиком, табличкой, крестиком, козликом и т.д. Соответственно, единственный правильный вариант это вот такой вот псевдокод:
if (!(errno is in (
EAGAIN,
EWOULDBLOCK,
EINTR,
ENOSPC,
ENOBUFS,
ENOMEM
))
{
...
}
Как это записать в современном C++, чтобы не было performance penalty? Без конструирования контейнера и т.п. Нормальных макросов же (как в Немерле), насколько я понимаю, не завезли?
В Beatles играло три с половиной человека — Леннон, Харрисон, Старр и пол-МакКартни.
A>А чтобы, значит, таких ошибок не допускать, он предлагал форматирование.
A>
A>if (!( errno == EAGAIN
A> || EWOULDBLOCK
A> || errno == EINTR
A> || errno == ENOSPC
A> || errno == ENOBUFS
A> || errno == ENOMEM)) {
A>
A>С моей точки зрения это глупость.
да нормальный это подход, ничего в нем глупого нет. Табличное форматирование хорошо помогает видеть нарушения структурности, если его использовать побольше
A>Код надо писать так, чтобы его нельзя было записать неправильно хоть в строчку, хоть столбиком, табличкой, крестиком, козликом и т.д. Соответственно, единственный правильный вариант это вот такой вот псевдокод:
A>
A>if (!(errno is in (
A> EAGAIN,
A> EWOULDBLOCK,
A> EINTR,
A> ENOSPC,
A> ENOBUFS,
A> ENOMEM
A> ))
A>{
A>...
A>}
A>
A>Как это записать в современном C++, чтобы не было performance penalty? Без конструирования контейнера и т.п. Нормальных макросов же (как в Немерле), насколько я понимаю, не завезли?
Здравствуйте, Alekzander, Вы писали:
A>Тут недавно была статья от создателей PVS, как надо и не надо писать код. В ней автор приводил следующий пример с ошибкой:
A>
A>void adns__querysend_tcp(adns_query qu, struct timeval now) {
A> ...
A> if (!(errno == EAGAIN || EWOULDBLOCK ||
A> errno == EINTR || errno == ENOSPC ||
A> errno == ENOBUFS || errno == ENOMEM)) {
A> ...
A>}
A>
Здравствуйте, fk0, Вы писали:
A>>Тут недавно была статья от создателей PVS, как надо и не надо писать код. В ней автор приводил следующий пример с ошибкой:
A>>
Здравствуйте, Alekzander, Вы писали:
fk0>> switch-case. В голом C даже.
A>Предикат через switch-case... такое. Тем более, в данном случае по невнимательности ошибок ещё больше настряпаешь, чем с простым if'ом.
inline-функция или лямбда (без захвата контекста), соптимизируется с ходу.
void adns__querysend_tcp(adns_query qu, struct timeval now) {
auto is_err = false;
switch(errno) {
case EAGAIN:
case EWOULDBLOCK:
case EINTR:
case ENOSPC:
case ENOBUFS:
case ENOMEM:
is_err = true;
}
if (!is_err) {
то возникнет ошибка компиляции на платформах, где EAGAIN == EWOULDBLOCK. Тогда как на платформах, где это разные значения, все будет нормально.
При этом тупое сравнение (errno == EAGAIN || errno == EWOULDBLOCK || ...) будет нормально компилироваться всегда.
A>Спасибо, сразу вопросы. Лишний call выкинут все компиляторы?
Я бы посмотрел на те компиляторы, которые интересны. Крайне рекомендую Compiler explorer для подобных исследований.
Например, по ссылке выше можно увидеть, что gcc/clang делают встроенный код, идентичный "ручному" сравнению для подходов через variadic non-type temlate args и через initializer_list.
При этом, для подхода через массив значений (он может быть удобен для случаев, когда нужно дать имя списку значений для переиспользования, и когда не хочется городить именнованные компайл-тайм списки) gcc даёт такой же код, а clang — таки делает массив.
А мсвц делает код "идентичный натуральному" только при подходе через variadic non-type temlate args, а для initializer_list и массива вставляет поиск (`call __std_find_trivial_4`)
A>Есть стандартная реализация?
Я такой не знаю. Для массива и initializer_list (см. примеры по ссылке выше) можно использовасть std::ranges::contains, но код получается хуже, чем через std::find. Впрочем, для msvc он один фиг неоптимальный.
Здравствуйте, so5team, Вы писали:
S>Для себя сделаю вывод, что если стандарт не вызубрен наизусть, то безопаснее все-таки написать (false || ... || (set == val))
Ну тут же логично всё, на мой взгляд, без зазубривания.
`||...` читай как "среди перечисленного существует такое, что...". Если список "перечисленного" пуст, то и не "существует такое что".
`&&...` читай как "для каждого перечисленного верно...". Если список "перечисленного" пуст, то для всех перечисленных условие выполняется (не существует такого в перечисленном, для которого не выполняется).
Здравствуйте, serg_joker, Вы писали:
A>>Спасибо, сразу вопросы. Лишний call выкинут все компиляторы? _>Я бы посмотрел на те компиляторы, которые интересны. Крайне рекомендую Compiler explorer для подобных исследований. _>Например, по ссылке выше можно увидеть, что gcc/clang делают встроенный код, идентичный "ручному" сравнению для подходов через variadic non-type temlate args и через initializer_list. _>При этом, для подхода через массив значений (он может быть удобен для случаев, когда нужно дать имя списку значений для переиспользования, и когда не хочется городить именнованные компайл-тайм списки) gcc даёт такой же код, а clang — таки делает массив. _>А мсвц делает код "идентичный натуральному" только при подходе через variadic non-type temlate args, а для initializer_list и массива вставляет поиск (`call __std_find_trivial_4`)
Честно сказать, я ждал ответа, что даже не сомневайся, все делают! А если надо посмотреть, всё плохо Но всё равно спасибо за ссылку!
A>>Есть стандартная реализация? _>Я такой не знаю. Для массива и initializer_list (см. примеры по ссылке выше) можно использовасть std::ranges::contains, но код получается хуже, чем через std::find. Впрочем, для msvc он один фиг неоптимальный.
Чего только нет в std... Ничего нет!
В Beatles играло три с половиной человека — Леннон, Харрисон, Старр и пол-МакКартни.
Здравствуйте, Alekzander, Вы писали:
A>Честно сказать, я ждал ответа, что даже не сомневайся, все делают! А если надо посмотреть, всё плохо Но всё равно спасибо за ссылку!
Сомневаться и проверять вообще полезно, не только в программировании.
A>Чего только нет в std... Ничего нет!
В std Много чего нет, но много чего и есть. И список этого "чего есть" растёт, хоть и не с такой скоростью (или не с тем качеством), как этого кому-нибудь может хотеться.
А есть языки, в которых есть всё, чего хочется и в самом языке, и в стандартной библиотеке? Если да, то будет разумным переходить на них.
Если нет, то стоит принять неидеальность рабочего инструмента и развивать свои навыки его использования.
Здравствуйте, Alekzander, Вы писали:
A>С моей точки зрения это глупость. Код надо писать так, чтобы его нельзя было записать неправильно хоть в строчку, хоть столбиком, табличкой, крестиком, козликом и т.д.
Здравствуйте, Alekzander, Вы писали:
A>Как это записать в современном C++, чтобы не было performance penalty? Без конструирования контейнера и т.п. Нормальных макросов же (как в Немерле), насколько я понимаю, не завезли?
switch(errno)
case EAGAIN:
case EWOULDBLOCK:
case EINTR:
case ENOSPC:
case ENOBUFS:
case ENOMEM:
{...}
Здравствуйте, student__, Вы писали:
A>>С моей точки зрения это глупость. Код надо писать так, чтобы его нельзя было записать неправильно хоть в строчку, хоть столбиком, табличкой, крестиком, козликом и т.д.
__>Юношеский максимализм.
Сочувствую.
В Beatles играло три с половиной человека — Леннон, Харрисон, Старр и пол-МакКартни.