Инструкция: в то время как по сравнению с для

Изменено в Блоге Питера Джута

Выравнивание структуры C основано на собственном типе наибольшего размера в структуре, по крайней мере, в целом (исключение составляет нечто вроде использования 64-битного целого на win32, где требуется только 32-битное выравнивание).

Если у вас есть только символы и массивы символов, как только вы добавите int, этот int будет начинаться с 4-байтовой границы (с возможным скрытым заполнением перед элементом int). Кроме того, если структура не кратна sizeof (int), в конце будет добавлено скрытое заполнение. То же самое для коротких и 64-битных типов.

Пример:

struct blah1 {
    char x ;
    char y[2] ;
};

sizeof (blah1) == 3

struct blah1plusShort {
    char x ;
    char y[2] ;
    // <<< hidden one byte inserted by the compiler here
    // <<< z will start on a 2 byte boundary (if beginning of struct is aligned).
    short z ;
    char w ;
    // <<< hidden one byte tail pad inserted by the compiler.
    // <<< the total struct size is a multiple of the biggest element.
    // <<< This ensures alignment if used in an array.
};

sizeof (blah1plusShort) == 8

6
задан Matthieu M. 21 October 2009 в 11:59
поделиться

9 ответов

Не все циклы предназначены для итераций:

while(condition) // read e.g.: while condition holds
{
}

в порядке, хотя это кажется вынужденным:

for(;condition;)
{
}

Вы часто видите это для любых источников ввода.

У вас также может быть неявная итерация:

while(obj.advance())
{
}

Опять же, это выглядит принудительно с for.

Кроме того, при принудительном использовании для вместо , а люди склонны злоупотреблять им:

for(A a(0); foo.valid(); b+=x); // a and b don't relate to loop-control
7
ответ дан 8 December 2019 в 14:44
поделиться

Функционально, конечно, это одно и то же. Единственная причина для дифференциации - придать какой-то смысл сопровождающему или человеку, читающему / обозревателю кода.

Я думаю, что идиома while полезна для сообщения читателю кода, что нелинейный тест контролирует цикл, тогда как идиома for обычно подразумевает некую последовательность. Мой мозг также как бы «ожидает», что циклы for контролируются только секцией счетного выражения аргументов оператора for, и я удивлен (и разочарован), когда обнаруживаю, что кто-то условно возится с индексной переменной внутри исполнительного блока.

Вы можете указать в своем стандарте кодирования, что циклы for должны использоваться только тогда, когда выполняется полная конструкция цикла for: индекс должен быть инициализирован в секции инициализатора, индекс должен быть протестирован в секции проверки цикла, а значение индекса должно быть изменено только в секции выражения подсчета. Любой код, который хочет изменить индекс в исполняемом блоке, должен вместо этого использовать конструкцию while. Обоснованием было бы «вы можете доверять выполнению цикла for, используя только те условия, которые вы видите, без необходимости искать скрытые операторы, изменяющие индекс, но вы не можете предположить, что что-то истинно в цикле while»

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

4
ответ дан 8 December 2019 в 14:44
поделиться

i не увеличивается автоматически в пределах цикла while.

while (i < 5) {

   // do something with X

   if (X) {
       i++;
   }

}
2
ответ дан 8 December 2019 в 14:44
поделиться

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

Как вы заметили, цикл for - это просто более компактный способ сказать

type counter = 0;
while ( counter != end_value )
{
  // do stuff
  ++counter;
}

Хотя его синтаксис достаточно гибкий, чтобы вы могли делать с ним другие вещи, я стараюсь ограничить свое использование из для в примеры, которые не намного сложнее, чем приведенные выше. OTOH, я бы не стал использовать цикл while для вышеуказанного.

1
ответ дан 8 December 2019 в 14:44
поделиться

Одна из самых прекрасных вещей в C ++ - это часть алгоритмов STL. При чтении кода, правильно написанного с использованием STL, программист будет читать циклы высокого уровня вместо циклов низкого уровня .

2
ответ дан 8 December 2019 в 14:44
поделиться

Я предпочитаю использовать для циклов, когда идет какой-то счет, и цикл заканчивается, когда счет заканчивается. Очевидно, у вас есть стандартный для (i = 0; i , но также есть такие вещи, как для (iterator.first ();! Iterator.is_done (); iterator.next ( )) .

Я использую while циклы, когда неясно, сколько раз цикл может повторяться, то есть «цикл до тех пор, пока какое-то условие, которое не может быть предварительно вычислено, выполняется (или не выполняется) ".

0
ответ дан 8 December 2019 в 14:44
поделиться
// I am also a fan of typedefs
for (const_iterator it = myVector.begin(), end = myVector.end();
     it != end && isValid(*it);
     ++it)
{ /* do stuff */ }

Мне кажется, что приведенный выше код менее читабелен, чем код ниже.

// I am also a fan of typedefs
const_iterator it = myVector.begin();
end = myVector.end();
while(it != end && isValid(*it))
{
    /* do stuff */ 
    ++it}

Лично я считаю, что удобочитаемость превосходит такие стандарты форматирования. Если другой программист не может легко прочитать ваш код, это в худшем случае приводит к ошибкам, а в лучшем - к потере времени, которое стоит денег компании.

0
ответ дан 8 December 2019 в 14:44
поделиться

Я бы не стал так быстро отбрасывать циклы do-while. Они полезны, если вы знаете, что тело вашего цикла будет выполнено хотя бы один раз. Рассмотрим код, который создает один поток на каждое ядро ​​процессора. В случае цикла for это может появиться:

for (int i = 0; i < number_of_cores; ++i)
    start_thread(i);

При входе в цикл первое, что проверяется, - это условие, в случае если number_of_cores равно 0, и в этом случае тело цикла никогда не должно выполняться. Но погоди - это лишняя проверка! У пользователя всегда будет хотя бы одно ядро, иначе как работает текущий код? Компилятор не может исключить первое избыточное сравнение, насколько ему известно, number_of_cores может быть 0. Но программист знает лучше. Итак, исключив первое сравнение:

int i = 0;
do {
    start_thread(i++);
} while (i < number_of_cores);

Теперь каждый раз, когда выполняется этот цикл, выполняется только одно сравнение вместо двух на одноядерной машине (с циклом for условие истинно для i = 0, ложно для i = 1, тогда как do while ложно все время). Первое сравнение опущено, поэтому оно быстрее. С меньшим потенциалом ветвления меньше вероятность ошибочных прогнозов ветвления, поэтому это быстрее. Поскольку условие while теперь более предсказуемо (всегда ложно на 1-ядерном), предсказатель ветвления может работать лучше, а это быстрее.

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

вероятность ошибочных прогнозов ветвей меньше, поэтому это быстрее. Поскольку условие while теперь более предсказуемо (всегда ложно на 1-ядерном), предсказатель ветвления может работать лучше, а это быстрее.

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

вероятность ошибочных прогнозов ветвей меньше, поэтому это быстрее. Поскольку условие while теперь более предсказуемо (всегда ложно на 1-ядерном), предсказатель ветвления может работать лучше, а это быстрее.

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

0
ответ дан 8 December 2019 в 14:44
поделиться

В Ye Olde C циклы for и while не были одинаковыми.

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

int i;
for (i = 0; i < N; i++) {
    if (f(i)) break;
}

printf("%d", i);           /* Non-defined behaviour, unexpected results ! */

Я не уверен на 100%, но я считаю, что это описано в K&R

Это нормально:

int i = 0;
while (i < N) {
    if (f(i)) break;
    i++;
}
printf("%d", i);

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

0
ответ дан 8 December 2019 в 14:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: