Вопрос

Что делает , оператор do в C?

Это было полезно?

Решение

Выражение:

(expression1,  expression2)

Сначала вычисляется expression1, затем expression2, и значение expression2 возвращается для всего выражения.

Другие советы

Я видел, как большинство использовалось в 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);
}

Тот Самый оператор запятой вычислит левый операнд, отбросит результат, а затем вычислит правый операнд, и это будет результат.Тот Самый идиоматический используется, как указано в ссылке, при инициализации переменных, используемых в for цикл, и это приводит к следующему примеру:

void rev(char *s, size_t len)
{
  char *first;
  for ( first = s, s += len - 1; s >= first; --s)
      /*^^^^^^^^^^^^^^^^^^^^^^^*/ 
      putchar(*s);
}

В остальном их не так уж много великий использование оператор запятой, хотя это и так легко злоупотреблять генерировать код, который трудно читать и поддерживать.

Из самого проект стандарта C99 грамматика выглядит следующим образом:

expression:
  assignment-expression
  expression , assignment-expression

и пункт 2 говорит:

Тот Самый левый операнд оператора запятой вычисляется как пустое выражение; после его оценки существует точка последовательности.Затем вычисляется правильный операнд;результат имеет свой тип и значение. 97) Если предпринимается попытка изменить результат оператора запятой или получить к нему доступ после следующей точки последовательности, поведение не определено.

Сноска 97 говорит:

Оператор запятой выполняет не дает значения lvalue.

это означает, что вы не можете присвоить результату оператор запятой.

Важно отметить, что оператор запятой имеет самый низкий приоритет и поэтому бывают случаи, когда использование () может иметь большое значение, например:

#include <stdio.h>

int main()
{
    int x, y ;

    x = 1, 2 ;
    y = (3,4) ;

    printf( "%d %d\n", x, y ) ;
}

будет иметь следующий результат:

1 4

Оператор запятой объединяет два выражения по обе стороны от него в одно, вычисляя их оба в порядке слева направо.Значение в правой части возвращается как значение всего выражения. (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));

Я не утверждаю, что какой-либо из этих примеров является хорошим стилем!Действительно, я, кажется, помню слова Стива Макконнелла Код Завершен советую даже не использовать операторы с запятой в for петля:для удобства чтения и сопровождения цикл должен управляться только одной переменной, а выражения в for сама строка должна содержать только код управления циклом, а не другие дополнительные биты инициализации или обслуживания цикла.

Это вызывает вычисление нескольких операторов, но использует только последний из них в качестве результирующего значения (rvalue, я думаю).

Итак...

int f() { return 7; }
int g() { return 8; }

int x = (printf("assigning x"), f(), g() );

должно привести к тому, что x будет установлено равным 8.

Оператор запятой не делает ничего значимого, это на 100% лишняя функция.Основное применение этого - "люди пытаются быть умными" и, следовательно, используют его для (непреднамеренного) запутывания читаемого кода.Основная область применения - это запутывание циклов for, например:

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: 2004 и MISRA-C: 2012 с обоснованием того, что он создает менее читаемый код.

Как указывалось в предыдущих ответах, он вычисляет все операторы, но использует последний в качестве значения выражения.Лично я нашел это полезным только в выражениях цикла:

for (tmp=0, i = MAX; i > 0; i--)

Единственное место, где я видел, что это полезно, - это когда вы пишете сложный цикл, где вы хотите выполнить несколько действий в одном из выражений (вероятно, выражение 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 вместо объявления и последующей инициализации....бла-бла-бла.)

Я восстанавливаю это просто для того, чтобы ответить на вопросы от @Rajesh и @JeffMercado, которые, я думаю, очень важны, поскольку это один из лучших хитов поисковой системы.

Возьмем, к примеру, следующий фрагмент кода

int i = (5,4,3,2,1);
int j;
j = 5,4,3,2,1;
printf("%d %d\n", i , j);

Он будет печатать

1 5

Тот Самый i обращение рассматривается так, как описано в большинстве ответов.Все выражения вычисляются в порядке слева направо, но только последнее из них присваивается i.В результате ( выражение )is1`.

Тот Самый j обращение следует другим правилам приоритета, поскольку , имеет наименьший приоритет оператора.Из-за этих правил компилятор видит присваивание-выражение, константа, constant ....Выражения снова вычисляются в порядке слева направо, и поэтому их побочные эффекты остаются видимыми, j является 5 в результате j = 5.

Интересно, int j = 5,4,3,2,1; это не разрешено спецификацией языка.Ан инициализатор ожидает, что присваивание-выражение таким образом, прямой , оператор не допускается.

Надеюсь, это поможет.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top