Оператор запятой объединяет два выражения по обе стороны от него в одно, оценивая их оба в порядке слева направо. Значение с правой стороны возвращается как значение всего выражения.
(expr1, expr2)
похоже на { expr1; expr2; }
, но вы можете использовать результат expr2
при вызове функции или назначении.
В циклах for
часто можно увидеть инициализацию или поддержку нескольких переменных, например:
for (low = 0, high = MAXSIZE; low < high; low = newlow, high = newhigh)
{
/* do something with low and high and put new values
in newlow and newhigh */
}
Кроме того, я использовал его «в гневе» только в одном другом случае, когда оборачивал две операции, которые всегда должны идти вместе в макросе. У нас был код, который копировал различные двоичные значения в байтовый буфер для отправки по сети, и указатель сохранялся там, где мы получили:
unsigned char outbuff[BUFFSIZE];
unsigned char *ptr = outbuff;
*ptr++ = first_byte_value;
*ptr++ = second_byte_value;
send_buff(outbuff, (int)(ptr - outbuff));
Где значения были short
с или int
с, мы сделали это:
*((short *)ptr)++ = short_value;
*((int *)ptr)++ = int_value;
Позже мы читаем, что это не был действительно C, потому что (short *)ptr
больше не является l-значением и не может быть увеличено, хотя наш компилятор в то время не возражал. Чтобы исправить это, мы разделили выражение на две части:
*(short *)ptr = short_value;
ptr += sizeof(short);
Тем не менее, этот подход основывался на том, что все разработчики не забывают вставлять оба утверждения все время. Мы хотели функцию, в которой вы могли бы передать выходной указатель, значение и и тип значения. Это C, а не C ++ с шаблонами, у нас не могло быть функции, принимающей произвольный тип, поэтому мы остановились на макросе:
#define ASSIGN_INCR(p, val, type) ((*((type) *)(p) = (val)), (p) += sizeof(type))
Используя оператор запятой, мы могли использовать его в выражениях или выражениях так, как нам хотелось:
if (need_to_output_short)
ASSIGN_INCR(ptr, short_value, short);
latest_pos = ASSIGN_INCR(ptr, int_value, int);
send_buff(outbuff, (int)(ASSIGN_INCR(ptr, last_value, int) - outbuff));
Я не предполагаю, что эти примеры являются хорошим стилем! В самом деле, я помню, что Стив Макконнелл Code Complete рекомендовал не использовать даже запятые в цикле for
: для удобства чтения и поддержки цикл должен управляться только одной переменной, а выражения в for
сама строка должна содержать только код управления циклом, а не другие дополнительные биты инициализации или обслуживания цикла.