Использует ли блок while ничего плохого? - PullRequest
23 голосов
/ 15 января 2009

В настоящее время я работаю над упражнениями на языке программирования Си. Вот одно из моих решений:

int c;

while ((c=getchar()) != EOF) {

if (c == ' ') {

    while ((c = getchar()) == ' ')

    {}  // do nothing?

    putchar(' ');

}

putchar(c);

}

Я нашел несколько решений здесь , которые сильно отличаются от моих и используют дополнительную переменную для отслеживания происходящего, тогда как я просто использую цикл while для пропуска всех пробелов. Мое решение кажется немного грязным, так как кажется немного хакерским иметь цикл while без фигурных скобок. Мне было интересно, есть ли веские причины не делать этого? Спасибо за любой совет :-)

Ответы [ 12 ]

37 голосов
/ 15 января 2009

Вовсе нет - я полагаю, что в K & R вы найдете такие петли, которые ничего не делают, так что это примерно настолько официально, насколько это возможно.

Это вопрос личных предпочтений, но я предпочитаю свои циклы бездействия, подобные этой:

while(something());

Другие предпочитают, чтобы точка с запятой шла на отдельной строке, чтобы подчеркнуть тот факт, что это цикл:

while(something())
  ;

Третьи предпочитают использовать скобки, в которых ничего нет, как вы уже сделали:

while(something())
{
}

Это все верно - вам просто нужно выбрать стиль, который вам нравится, и придерживаться его.

6 голосов
/ 15 января 2009

Ваш вопрос "Использование блока while для ничего плохого?" можно также ответить с точки зрения траты циклов процессора. В этом случае ответ «Нет», поскольку процесс будет находиться в режиме ожидания, пока пользователь ожидает ввода символа.

Процесс будет активирован только после ввода символа. Затем будет выполнен тест, и если тест пройден, т.е. c == '', процесс снова перейдет в спящий режим, пока не будет введен следующий символ. Это повторяется до тех пор, пока не будет введен непробельный символ.

4 голосов
/ 15 января 2009

Ну, если вам действительно не нравятся пустые скобки, вы можете преобразовать этот внутренний цикл в

while (c == ' ') {c = getchar();}

Это стоит одного дополнительного сравнения, поэтому цикл с делом будет лучше.

4 голосов
/ 15 января 2009

Я думаю, что это вполне приемлемо.

Я бы написал так:

//skip all spaces
while ((c = getchar()) == ' ') {} 

чтобы сделать очевидным, что эта строка кода делает одну вещь.

Или я бы написал так:

while ((c = getchar()) == ' ') {
    //no processing required for spaces
}

, чтобы он соответствовал остальному формату вашего кода.

Лично я не фанат

while ((c = getchar()) == ' ');

формат. Я думаю, что легко не заметить точку с запятой.

2 голосов
/ 15 января 2009

Я не думаю, что процедура такова, но ваше форматирование довольно странное. В этом нет ничего плохого:

/* Eat spaces */
while ((c = getchar()) == ' ');

(то есть указать, что там намеренно нет тела)

1 голос
/ 15 января 2009

A while, который ничего не делает, вероятно это плохо:

while(!ready) {
   /* Wait for some other thread to set ready */
}

... это действительно очень дорогой способ ожидания - он будет использовать столько ЦП, сколько ОС даст ему, до тех пор, пока ready ложно, кража времени ЦП, с которым другой поток может делать полезную работу.

Однако ваш цикл не ничего не делает:

while ((c = getchar()) == ' ')
    {};  // skip

... потому что он вызывает getchar() на каждой итерации. Следовательно, как и все остальные, все, что вы сделали, прекрасно.

1 голос
/ 15 января 2009

Я бы предпочел:

while ((c = getchar()) == ' ') /* Eat spaces */;

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

Хотя несуществующие тела петель вполне приемлемы, должно быть ОЧЕНЬ ясно, что это преднамеренно.

0 голосов
/ 15 января 2009

Ну, не совсем, но это зависит от вашей архитектуры.

if (dosomething()) { ; }

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

0 голосов
/ 15 января 2009

Альтернативный вариант, который еще не был упомянут:

while(condition)
    (void)0;

Я действительно не предпочитаю писать свои циклы таким образом , но у меня был последний семестр TA, который сделал.

0 голосов
/ 15 января 2009

Канонический способ - использовавшийся с незапамятных времен, взгляните, например, на Лионскую книгу -

while(condition)       // Here's the whole thing
    ;                  // empty body.

На самом деле, в общем случае соглашение «точка с запятой в отдельной строке» используется для нулевого оператора. Например, иногда вы увидите

if( condition-1)
     ;
else if (condition-2)
     stmt;
else {
     // do stuff here
}

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

while(condition) ;

формы нужно рабски избегать, потому что это распространенная и раздражающая опечатка: вы должны дать понять, что сделали это нарочно. Пустые скобки

 while(condition){
 }

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...