Это обратная ссылка.
Из http://www.selectorweb.com/grep_tutorial.html :
Backreference - это выражение\n, где n - число. Он соответствует содержимому n-го набора круглых скобок в выражении.
Кроме того, ответ: (d):
$ grep -E '(^.{4})(.{2}).*[ ]\2' test.txt If there's a bustle in your hedgerow.
Выражение:
(expression1, expression2)
Вычисляется первое выражение1, затем вычисляется выражение 2, и значение выражения2 возвращается для всего выражения.
Он вызывает оценку нескольких операторов, но использует только последнее значение в качестве результирующего значения (rvalue, я думаю).
Итак ...
int f() { return 7; }
int g() { return 8; }
int x = (printf("assigning x"), f(), g() );
should результат: x устанавливается в 8.
Оператор comma будет оценивать левый операнд, отбрасывать результат и затем оценивать правый операнд, и это будет результат. Использование идиоматического , как указано в ссылке, при инициализации переменных, используемых в цикле for
, и дает следующий пример:
void rev(char *s, size_t len)
{
char *first;
for ( first = s, s += len - 1; s >= first; --s)
/*^^^^^^^^^^^^^^^^^^^^^^^*/
putchar(*s);
}
В противном случае их не так много great использует оператор запятой , хотя легко злоупотреблять , чтобы генерировать код, который трудно читать и поддерживать.
Из черновика стандарта C99 грамматика выглядит следующим образом:
expression:
assignment-expression
expression , assignment-expression
и параграф 2 говорит:
Левый операнд оператора запятой оценивается как выражение void; после его оценки появляется точка последовательности. Затем оценивается правый операнд; результат имеет свой тип и значение. 97). Если делается попытка изменить результат работы с запятой или получить доступ к ней после следующей точки последовательности, поведение не определено.
blockquote>Сноска 97 говорит:
Оператор запятой не дает lvalue.
blockquote>, что означает, что вы не можете назначить результат запятой .
Важно отметить, что оператор с запятой имеет самый низкий приоритет , и поэтому бывают случаи, когда использование
()
может иметь большое значение, например:#include <stdio.h> int main() { int x, y ; x = 1, 2 ; y = (3,4) ; printf( "%d %d\n", x, y ) ; }
будет иметь следующий выход:
1 4
Как было сказано ранее, он оценивает все утверждения, но использует последнее в качестве значения выражения. Лично я нашел его полезным в выражениях цикла:
for (tmp=0, i = MAX; i > 0; i--)
Оператор запятой объединяет два выражения с обеих сторон в один, оценивая их как в порядке слева направо. Значение правой части возвращается как значение всего выражения. (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
s или int
s мы сделали это:
*((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
сама строка должна содержать только код управления контуром, а не другие дополнительные биты инициализации или обслуживания цикла.
Оператор запятой не делает ничего значимого, это 100% избыточная функция. Основное его использование - «люди, пытающиеся быть умными» и, следовательно, использовать их для (непреднамеренно) обфускации читаемого кода. Основной областью использования является обфускация для циклов, например:
for(int i=0, count=0; i<x; i++, count++)
Если int i=0, count=0
на самом деле не является оператором запятой, а является списком деклараций (мы уже смущены здесь). i++, count++
- это оператор запятой, который сначала оценивает левый операнд, а затем правый операнд. Результатом оператора запятой является результат правильного операнда. Результат левого операнда отбрасывается.
Но приведенный выше код можно записать гораздо более читаемым способом без оператора запятой:
int count = 0;
for(int i=0; i<x; i++) // readable for loop, no nonsense anywhere
{
...
count++;
}
Единственный реальный использование оператора запятой, который я видел, является искусственным обсуждением точек последовательности, поскольку оператор запятой имеет точку последовательности между оценкой левого и правого операндов.
Итак, если у вас есть неопределенный код поведения например:
printf("%d %d", i++, i++);
Фактически вы можете превратить его в просто неопределенное поведение (порядок оценки параметров функции), написав
printf("%d %d", (0,i++), (0,i++));
. Теперь есть точка последовательности между оценка i++
, поэтому, по крайней мере, программа не будет рисковать, чтобы сбой и сжечь дольше, хотя порядок оценки параметров функции остается неуказанным.
Конечно, никто не напишет такой код в реальном приложений, это полезно только для разговоров по языку-юристу о точках последовательности на языке С.
. Оператор запятой запрещен MISRA-C: 2 004 и MISRA-C: 2012 с обоснованием того, что он создает менее читаемый код.
for
, рассмотрите continue
. То, что вы предлагаете, эквивалентно действительности. Что касается читаемости, рассмотрим src++, dst++
, где сохранение обоих приращений вместе в коде значительно упрощает читателю проверку того, что оба указателя получают одинаковое увеличение.
– hvd
24 March 2015 в 18:20
src++, dst++;
более читабельна, чем src++; (newline) dst++;
. Я очень сомневаюсь.
– Lundin
25 March 2015 в 08:16
Единственное место, которое я видел в этом полезном, - это когда вы пишете цикл фанки, в котором вы хотите сделать несколько вещей в одном из выражений (возможно, выражение init или выражение цикла). Что-то вроде:
bool arraysAreMirrored(int a1[], int a2[], size_t size)
{
size_t i1, i2;
for(i1 = 0, i2 = size - 1; i1 < size; i1++, i2--)
{
if(a1[i1] != a2[i2])
{
return false;
}
}
return true;
}
Простите меня, если есть какие-либо синтаксические ошибки или если я смешался с чем-то, что не является строгим C. Я не утверждаю, что оператор является хорошей формой, но для этого вы можете использовать его. Вероятно, вместо этого используется цикл while
, поэтому несколько выражений в init и loop будут более очевидными. (И я инициализировал i1 и i2 inline вместо объявления и затем инициализации .... blah blah blah.)
Я видел больше всего в циклах while
:
string s;
while(read_string(s), s.len() > 5)
{
//do something
}
Он выполнит операцию, затем выполнит тест, основанный на побочном эффекте. Другой способ - сделать это следующим образом:
string s;
read_string(s);
while(s.len() > 5)
{
//do something
read_string(s);
}
while (read_string(s) && s.len() > 5)
. Очевидно, что это не сработает, если read_string
не имеет возвращаемого значения (или не имеет значимого). (Изменить: Извините, не заметил, сколько лет этот пост был.)
– jamesdlin
25 March 2010 в 09:05
while (1)
с выражением break;
в теле. Пытаясь заставить прорывную часть кода перейти во время теста или вниз в тест-тест, часто является пустой тратой энергии и делает код более сложным для понимания.
– potrzebie
27 September 2012 в 07:20
while(1)
и break
;
– Michael
11 March 2016 в 15:19
i
не будет иметь значений 5, 4, 3, 2 или 1. Это просто 0. Это практически бесполезно, если выражения не имеют побочных эффектов. – Jeff Mercado 13 November 2010 в 08:06