Как называется эта функция C ++?

82

Я писал код на C ++ и по ошибке пропустил имя функции WSASocket. Однако мой компилятор не выдал ошибку и связал my SOCKETс целочисленным значением 1 вместо действительного сокета.

Рассматриваемый код должен был выглядеть так:

this->listener = WSASocket(address->ai_family, address->ai_socktype, address->ai_protocol, NULL, NULL, WSA_FLAG_OVERLAPPED);

Но вместо этого это выглядело так:

this->listener = (address->ai_family, address->ai_socktype, address->ai_protocol, NULL, NULL, WSA_FLAG_OVERLAPPED);

Исходя из других языков, похоже, что это какой-то анонимный тип. Как называется функция, если это действительно функция?

Какова его цель?

Его сложно искать, когда не знаешь, с чего начать.

Майкл Дж. Грей
источник
3
+1, хороший вопрос для викторины в пабе (или ужасный вопрос на собеседовании для фирм, которые любят нанимать людей, которые хорошо разбираются в головоломках).
Вирсавия
8
Ссылка на статью в Википедии об операторе запятой . FWIW, одно из распространенных применений - получение двух побочных эффектов в forвыражении цикла * итерация , ala для (int i = 0, j = 0; i <10; ++ i, --j) ... `
Тони Делрой
1
@ MichaelJ.Gray Технически вы ошибаетесь. Это не перезаписывает поведение. Представьте:i=0;j=0;x=i++,j=6; x и j были бы 6, а я в любом случае был бы 1. Если поведение i ++ было бы перезаписано, оно осталось бы 0. Но каждый оператор вызывается, и после достижения ,только всех расширений отбрасываются, и вызывается следующая точка псевдопоследовательности. Таким образом, первый =просто назначает часть после последней, ,но каждая точка вызывается. В любом случае: я не понимаю, почему ваш компилятор не предупреждает вас о переопределении объявления функции, а вместо этого меняет ваш код на что-то
другое
5
Если вы используете правильный компилятор с включенными предупреждениями, он будет предупреждать о таком хитром коде, например, gccи g++с помощью-Wall опцией сказать:warning: left-hand operand of comma expression has no effect [-Wunused-value]
Сэм Уоткинс
3
Поэтому, на мой взгляд, лучший ответ на этот вопрос - «всегда включать предупреждения» - тогда компилятор сам объяснит, что произошла ошибка, и расскажет, что вы сделали; и этот ответ решит и для вас множество других проблем.
Сэм Уоткинс

Ответы:

151

Оператор запятая † вычисляет левую часть, отбрасывает ее значение и в результате возвращает правую часть. WSA_FLAG_OVERLAPPEDравно 1, и это результат выражения; все остальные значения отбрасываются. Никаких сокетов не создается.


† Если не перегружен. Да, может быть перегружен. Нет, не стоит его перегружать. Отойдите от клавиатуры прямо сейчас!

Р. Мартиньо Фернандес
источник
9
+1, дух ускорения очень эффективно перегружает оператор запятой, но это очень одинокое исключение из правила: не делайте этого .
Вирсавия
2
@Bathsheba Boost.Assign также перегружает оператор запятой, но кто использует это с C ++ 11?
rubenvb
39
Но у вас было лучшее объяснение того, насколько ужасной может быть запятая. Неумолимый и полный насмешек, он несколько минут мучил мой код, глядя на меня без стыда за свое поведение.
Майкл Дж. Грей
1
@ R.MartinhoFernandes - Eigen также очень эффективно перегружает оператор запятой. См. Этот вопрос SE для примера использования.
Дэвид Хаммен
22

Оператор запятой помогает понять ваш код.

Вы эффективно устанавливаете, this->listener = WSA_FLAG_OVERLAPPED;что просто синтаксически верно.

Вирсавия
источник
3
Действует не только синтаксически, но, поскольку Windows API небезопасен по типу, это также допустимое преобразование.
MSalters
5
@MSalters не то, что POSIX намного лучше в этом отношении
chbaker0
1
Вот почему конструкторы, вызываемые с одним аргументом, должны быть явными , тогда произошла бы ошибка компилятора, и разработчик мог бы еще раз взглянуть на эту причудливую конструкцию.
Matthieu M.
@MSalters Ну, SOCKETэто typedef для unsigned intи WSA_FLAG_OVERLAPPEDявляется intлитералом. Если SOCKETбы это было синонимом int, это даже не было бы обращением .
Joker_vD
1
@Joker_vD: Конечно. Если бы они сделали это typedef для struct __socket*, у нас было бы меньше ошибок. Но существует слишком много кода, который «знает» SOCKETявляется неотъемлемой частью.
MSalters
21

Компилятор по очереди оценивает каждую точку последовательности в круглых скобках, и результатом является последнее выражение WSA_FLAG_OVERLAPPEDв выражении.

Оператор запятая ,- это точка последовательности в C ++. Выражение слева от запятой полностью вычисляется раньше, чем выражение справа. Результатом всегда является значение справа. Когда у вас есть выражение в форме (x1, x2, x3, ..., xn), результат выражения всегда xn.

Шон
источник
После того, как вы добавили туда свое разъяснение, оно приобретает больше смысла. Сначала я не совсем понимал важность вопроса о точках последовательности.
Майкл Дж. Грей