В вашем примере кода используются две не очень известные новичкам (но не особо скрытые) функции выражений C:
- оператор запятой: обычный бинарный оператор, роль которого состоит в возвращении последнего из двух его операндов. Если операнды являются выражением, они оцениваются слева направо.
- присваивание в качестве оператора, возвращающего значение. Назначение Си не является оператором, как в других языках, и возвращает присвоенное значение.
В большинстве случаев использования обеих этих функций используется некоторая форма запутывания. Но есть некоторые законные. Дело в том, что вы можете использовать их везде, где можете предоставить выражение: внутри условного оператора if или while, в блоке итерации цикла for, в параметрах вызова функции (при использовании комы необходимо использовать скобки, чтобы не перепутать с фактическими параметрами функции) , в параметре макроса и т. д.
Наиболее распространенное использование запятой, вероятно, в управлении циклом, когда вы хотите изменить две переменные одновременно или сохранить какое-либо значение перед выполнением теста цикла или итерации цикла.
Например, обратная функция может быть написана, как показано ниже, благодаря оператору запятой:
void reverse(int * d, int len){
int i, j;
for (i = 0, j = len - 1 ; i < j ; i++, j--){
SWAP(d[i], d[j]);
}
}
Другое законное (на самом деле не запутанное) использование оператора комы, которое я имею в виду, - это макрос DEBUG, который я нашел в каком-то проекте, определенном как:
#ifdef defined(DEBUGMODE)
#define DEBUG(x) printf x
#else
#define DEBUG(x) x
#endif
Вы используете это как:
DEBUG(("my debug message with some value=%d\n", d));
Если DEBUGMODE включен, то вы получите printf, если не вызывать функцию-обертку, но выражение между круглыми скобками все еще допустимо C. Дело в том, что любой побочный эффект при печати кода будет применяться как в коде выпуска и отладочный код, подобный представленному:
DEBUG(("my debug message with some value=%d\n", d++));
С указанным выше макросом d всегда будет увеличиваться независимо от режима отладки или выпуска.
Вероятно, есть и другие редкие случаи, когда значения запятой и присваивания полезны, и код легче писать, когда вы их используете.
Я согласен, что оператор присваивания является отличным источником ошибок, поскольку его легко спутать с условием == в условном выражении.
Я согласен, что, поскольку запятая также используется с другим значением в других контекстах (вызовы функций, списки инициализации, списки объявлений), это был не очень хороший выбор для оператора. Но в принципе это не хуже, чем использование <и> для параметров шаблона в C ++, и существует в C с гораздо более старых дней.