Извините за новый вопрос. Я все еще изучаю программирование. Итак, я использую C++, и мне нужно сделать что-то вроде этого:
int n;
do {
n = get_data();
if (n != -1)
send(n);
} while(n != -1);
Это всего лишь набросок. В любом случае это не выглядит очень элегантно. Мне нужно сдать тест дважды. Я мог бы просто протестировать один раз и установить флаг, но это тоже не выглядит элегантным, поскольку мне нужно проверять флаг дважды. Просто кажется, что должен быть способ сделать это проще, потому что это так просто, что я хочу делать.





Как насчет использования перерыв:
int n;
while(1) {
n = get_data();
if (n == -1)
break;
send(n);
}
Таким образом, вы тестируете только один раз и немедленно завершаете работу, если get_data не возвращает то, что вы хотите.
Я предпочитаю это, потому что это наиболее выразительно и масштабируется, даже когда get_data () становится более сложным. В этом случае я бы также добавил комментарий, описывающий условие выхода к «вечному циклу», например // прерывается, когда get_data () == -1.
Это экземпляр хорошо известной конструкции «Полтора цикла»: cs.duke.edu/~ola/patterns/plopd/loops.html#loop-and-a-half
Самая очевидная и, следовательно, самая элегантная, для меня она важна.
int n;
while (-1 != (n = get_data())) {
send(n);
} // while
Я презираю, когда люди помещают константу в левой части сравнения.
Некоторых из моих бывших коллег оскорбляет эта конструкция (побочный эффект, встроенный в условное выражение), и в нескольких учебниках говорится, что этого не следует делать. Я никогда не понимал почему - я думаю, что это нормально, но иногда лучше избегать по политическим причинам.
Вы помещаете константу слева, так что это означает ошибку компилятора, когда вы случайно меняете == или! = На оператор присваивания (=). Это больше не проблема для большинства современных языков, особенно для современных IDE. Я до сих пор делаю это в коде C++.
Размещение константы в левой части выражения помогает избежать случайных ошибок, таких как if (n = -1)
Я удивлен, что никто не прокомментировал «// while» в конце такого короткого цикла.
Большинство компиляторов предупреждают о назначении внутри проверяемого оператора и заставляют вас заключить его в другой набор круглых скобок, чтобы обеспечить соблюдение ваших намерений. Если ваш компилятор не предупреждает об этом или вы игнорируете предупреждения, это ваша проблема, а не язык
Лично мне нравится -1 в правой части (немного легче читать (компилятор предупредит о назначении, и я компилирую с 0 предупреждениями)). У меня нет проблем с присваиванием в условиях, когда это делает код легко читаемым. В этой ситуации его читать намного легче, чем оригинал.
Цепляться за стандарты только потому, что это не уважительная причина. Первоочередная задача любого разработчика - поддержание кода. Все, что упрощает понимание (и, следовательно, поддержку) кода, отменяет большинство проблем.
Несмотря на состояние йоды, Джин мертв.
Ваша оригинальная версия в порядке.
В моей последней работе по программированию на C мы должны были следовать стандартам кодирования MISRA.
Согласно правилам MISRA это:
int n;
while(1) {
n = get_data();
if (n == -1)
break;
send(n);
}
запрещено из-за break, а это:
while((n = get_data()) != -1) { send(n); }
запрещено, потому что присваивание появляется в логическом контексте, поэтому я имею привычку писать циклы, аналогичные вашей исходной версии.
Вы можете использовать логическую переменную, если считаете, что это проясняет ваше намерение, или если тест представляет собой сложное выражение:
int n;
bool valid;
do {
n = get_data();
valid = n != -1;
if (valid)
send(n);
} while(valid);
Но для простого теста, такого как "n != -1", возможно, не стоит делать программу длиннее.
Я не смог найти онлайн-версию этого стандарта MISRA (хотя вы можете купить книгу за 25 долларов ...). Из вашего описания кажется глупым навязывать программисту громоздкий стиль кодирования.
@Harleqin, вы правы, результирующий код может быть громоздким, некоторые правила избыточны, а некоторые другие не имеют смысла за пределами встроенных платформ.
MISRA требует, чтобы код не был доступен только для записи. Его правила заключаются в том, чтобы сделать любую программу самоочевидной. Конечно, некоторые из них могут повысить производительность, но, как мы все знаем, оптимизацию следует производить после того, как у вас будет работающая программа. Если вы получаете четко читаемый код, вы позволяете другим использовать его повторно.
@ jpinto3912 - из этого примера кажется, что MISRA может иногда применять противоположное.
Подобно eed3si9n, но, возможно, легче читать:
int n;
while (n = get_data(), n != -1)
{
send(n);
}
Придется возразить против облегчения чтения. Большинство программистов не понимают оператора запятой в C и натыкаются на конструкции такого типа.
С другой стороны, многим программистам также трудно понять, что operator = возвращает присвоенное значение, и его использование может легко привести к ошибкам, упомянутым в другом месте. Но именно поэтому я сказал «возможно» вместо «определенно» :-)
Даже если вы не знакомы с запятой, эта версия выглядит намного чище. Я чувствую, что тот, кто видел это, но не привык к запятым, все равно сможет разобрать это быстрее, чем версия eed3si9n.
for (int n = get_data(); n != -1; n = get_data()) {
send(n);
}
Уберите фигурные скобки, если хотите сохранить строчку :)
Да, если вы действительно хотите сделать его короче (чего я не делаю), это будет лучший способ. По крайней мере, умное использование цикла for.
Постройте с goto :)
int n;
goto inside; do {
send(n);
inside:
n=get_data();
} while(n!=-1);
Нет разницы между циклом do и циклом while, если вы никогда не вводите его сверху, не так ли? В противном случае я бы использовал более знакомую форму «пока».
Да, вы правы, реальной разницы нет. Это дело личного вкуса :) Мне понравилась форма do-while, потому что строки с получением данных и строка с проверкой этих данных (условие цикла) располагаются одна за другой.
Обычно я бы проголосовал против, так как форматирование затрудняет чтение, но это интересный подход.
int get_data()
{
...
}
void _send(int )
{
...
}
int send(int (*a) ())
{
int n = a();
if (n == -1)
return n;
_send(n);
return 1;
}
int main()
{
int (*fp)();
fp = get_data;
while ( send(fp)!= -1 );
return 0;
}
HTH
int n;
n = get_data();
while (n != -1) {
send(n);
n = get_data();
}
Так учили делать петли в коболе еще тогда. Будет ли типичный компилятор скомпилировать это в эффективной форме? Из того, что я видел, решение lazydens обычно генерируется компилятором для повышения эффективности кеширования инструкций.
В Python вы бы сделали это:
while True:
n = get_data()
if n == -1:
break
send(n)
Как видите, это ненамного короче вашей версии C. Обычно код Python в 5-10 раз меньше, чем его эквивалент на C. Здесь дело обстоит не так, поэтому вы можете наслаждаться своим читаемым, достаточно коротким и быстрым сниппетом и сосредоточиться на чем-то другом.
Если вы хотите сделать его короче, проверьте ответ Джонатана, но на самом деле это не имеет значения.
/* This is cleaner */
AGAIN:;
int n = get_data();
if (n != -1)
{
send(n);
goto AGAIN;
}
/* This has some charm as well */
int n;
while ((n = get_data()) != -1)
send(n);
/* and now i see that this is the top answer. Oh well */
Честно говоря, ваш код легко читается. Потратить время на то, чтобы сделать его короче (и дать больше времени, чтобы распаковать его в голове, когда вы снова прочтете его), - не лучшее вложение, которое вы можете сделать. Кому интересно: работает, работает эффективно и читается. Перейти к следующим строкам.