Нужна помощь в понимании этого для кода цикла в C

Рассмотрим следующий код в C:

void main()
{
    int a=0;

    for(printf("\nA"); a; printf("\nB"));

    printf("\nC");
    printf("\nD");     
}

Когда я скомпилирую его с помощью Turb С++ версии 3.0 и gcc-4.3.4, я получаю следующее в качестве результата в BOTH случаях:

A
C
D

Однако, если я скомпилирую следующий код:

void main()
{
    for(printf("\nA"); 0; printf("\nB"));

    printf("\nC");
    printf("\nD");
}

Вывод gcc-4.3.4 такой же, как в предыдущем случае, но turbo С++ 3.0 производит следующий вывод:

A
B
C
D

Прежде всего, я понятия не имею, что здесь происходит! Кроме того, как получается, что результат компилятора gcc одинаковый для обоих кодов, но в случае компилятора turboС++ 3.0, результат отличается? Может кто-то пролить некоторый свет?

ИЗМЕНИТЬ:

На самом деле кого-то задавали этот вопрос в интервью для ИТ-компании, и когда он не дал ответа, интервьюер дал это объяснение. Но я считаю, что это глупо. Как вы можете попросить кого-нибудь использовать "ошибку", как если бы это было "средство", предоставляемое языком? Для того, чтобы он назывался "объектом" и "техникой", передаем ли мы 0 как литерал во втором выражении или переменную, значение которой равно 0, результат должен быть одинаковым.

Неужели я ошибаюсь, что интервьюер был очень глупым, чтобы задать такой вопрос и что он показывает свою некомпетентность?

Ответ 1

Выход TCC для второго примера неверен.

Из стандарта C99:

Утверждение

для выражения < выражения <1 > ; выражение <2 >

ведет себя следующим образом: выражение expression-2 является управляющим выражение, которое оценивается перед каждым исполнением тела цикла. Выражение expression-3 оценивается как выражение void после каждое выполнение тела цикла. [...]

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

Аналогично, в стандарте C90 (или, по крайней мере, в черновике, который я нашел), он говорит:

За исключением поведения оператора continue в теле цикла, Заявление

     for (  expression-1 ;  expression-2 ;  expression-3 )  statement

и последовательность операторов

      expression-1 ;
     while ( expression-2) {
               statement
              expression-3 ;
     }

эквивалентны.

Ответ 2

Turbo С++ 3.0 был выпущен в 1990-х годах и был очень быстро дополнен версией 3.1.

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

В любом случае гарантировано, что Turbo С++ 3.0 не поддерживается на вашей текущей платформе. Когда дело доходит до того, что компилятор не поддерживается, потому что платформа была создана почти 20 лет спустя, вы не можете действительно ошибочно ее исправить для неправильной программы.

Ответ 3

Выход gcc правильный.

Вывод Turbo С++ 3.0 в первом случае правильный.

Вывод TurboС++ 3.0 во втором случае неверен.

В компиляторе Turbo С++ 3.0 вы обнаружили, что кэш края, приводящий к некорректной генерации кода, обнаружил.

A for-stmt в C или С++ имеет общий синтаксис

для (инициализация, тест, повторная инициализация) stmt

Инициализация выполняется один раз до начала цикла. Тест выполняется в верхней части цикла. Если тест верен, выполняется stmt, а затем повторная инициализация и цикл повторяется.

В вашем случае printf ( "\nA" ) является инициализацией, а (или 0) является тестом, printf ( "\nB" ) является повторной инициализацией, а stmt пуст.

Вы должны были увидеть A (и вы сделали). Тест должен был провалиться с первого прохода, а это значит, что вы никогда не должны были видеть stmt (но вы не знаете), и вы никогда не должны были видеть B. Это то, что Turbo С++ 3.0 прикручивает второй тест.

Ответ 4

Что такое полный "для" синтаксис цикла в C (и другие, если они совместимы)?

Этот вопрос цитирует применимую часть стандарта. Третье выражение не должно оцениваться, если цикл не выполняется хотя бы один раз. Итак, я бы сказал, что во втором случае старый компилятор неправильно печатает "B".

Ответ 5

семантика for заключается в том, что первое выражение оценивается (инициализатор), тогда второе выражение оценивается (терминатор), а затем, если терминатор оценивается как ненулевое тело тела for, то третье выражение ( продвижение) оценивается и возвращается к оценке терминатора.

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

printf("\nA");
a; // yields 0 -> terminate loop

Это действительно то, что происходит.

В вашем втором примере то же самое должно произойти (как для gcc), так как 0 принимает значение 0.

Возможно, что турбо С++ - просмотр константы 0 - попытался выполнить какую-то оптимизацию разворачивания цикла (и не смог выполнить ее правильно)