Вам даже не нужно while
, вам просто нужно, чтобы иметь возможность сравнить и быть в состоянии расшириться, другими словами, if
и goto
. В следующей программе, функции test_normally()
и test_subnormally()
эквивалентны:
#include <stdio.h>
void exec1(void)
{
puts("exec1() called");
}
void exec2(void)
{
puts("exec2() called");
}
void exec3(void)
{
puts("exec3() called");
}
void test_normally(void)
{
int cond1 = 0;
int cond2 = 1;
int i = 5;
/* First if test */
if (cond1)
exec1();
else
exec2();
puts("First if test over.");
/* Second if test */
if (cond2)
exec1();
else
exec2();
puts("Second if test over.");
/* While test */
while (i > 0) {
exec3();
--i;
}
puts("Loop test over.");
}
void test_subnormally(void)
{
int cond1 = 0;
int cond2 = 1;
int i = 5;
/* First if test */
if (!cond1)
goto cond1_false;
exec1();
goto cond1_end;
cond1_false:
exec2();
cond1_end:
puts("First if test over.");
/* Second if test */
if (!cond2)
goto cond2_false;
exec1();
goto cond2_end;
cond2_false:
exec2();
cond2_end:
puts("Second if test over.");
/* While test */
loop_start:
if (!(i > 0))
goto loop_end;
exec3();
--i;
goto loop_start;
loop_end:
puts("Loop test over.");
}
int main(void)
{
test_normally();
putchar('\n');
test_subnormally();
return 0;
}
и выход:
[email protected]:~/src/sandbox$ ./goto
exec2() called
First if test over.
exec1() called
Second if test over.
exec3() called
exec3() called
exec3() called
exec3() called
exec3() called
Loop test over.
exec2() called
First if test over.
exec1() called
Second if test over.
exec3() called
exec3() called
exec3() called
exec3() called
exec3() called
Loop test over.
[email protected]:~/src/sandbox$
Сравнивая две функции, надеюсь, вы можете понять, почему if
и while
и все их друзья лучше чем альтернативы.
test_subnormally()
на самом деле очень близок к тому, что делает процессор, после того, как ваш источник C скомпилирован в машинный код. Вот результат сборки test_normally()
от ССЗ на 64 битном процессоре Intel - вы можете увидеть, что почти отображение взаимно-однозначное соответствие между инструкциями по сборке и источника C для другой функции, test_subnormally()
:
.LC3:
.string "First if test over."
.LC4:
.string "Second if test over."
.LC5:
.string "Loop test over."
.text
.globl test_normally
.type test_normally, @function
test_normally:
.LFB3:
.cfi_startproc # // Function entry
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $16, %rsp
movl $0, -8(%rbp) # // -8(%rbp) is cond1
movl $1, -12(%rbp) # // -12(%rbp) is cond2
movl $5, -4(%rbp) # // -4(%rbp) is i
cmpl $0, -8(%rbp) # if (!cond1)
je .L5 # goto cond1_false;
call exec1 # exec1();
jmp .L6 # goto cond1_end;
.L5: # cond1_false:
call exec2 # exec2();
.L6: # cond1_end:
movl $.LC3, %edi # // move "First if test over" to %edi
call puts # puts("First if test over");
cmpl $0, -12(%rbp) # if (!cond2)
je .L7 # goto cond2_false;
call exec1 # exec1();
jmp .L8 # goto cond2_end;
.L7: # cond2_false:
call exec2 # exec2();
.L8: # cond2_end:
movl $.LC4, %edi # // move "Second if test over" to %edi
call puts # puts("Second if test over");
jmp .L9 # goto loop_start;
.L10: # loop_body:
call exec3 # exec3();
subl $1, -4(%rbp) # --i;
.L9: # loop_start:
cmpl $0, -4(%rbp) # if (!(i > 0)) ...
jg .L10 # ...goto loop_body;
movl $.LC5, %edi # // move "Loop test over" to %edi
call puts # puts("Loop test over");
leave # // Function exit
.cfi_def_cfa 7, 8
ret
.cfi_endproc
Компилятор здесь решил поместить фрагменты цикла в несколько иной порядок, но кроме этого он читает почти так же, как источник C для test_subnormally()
. Основная причина, по которой мы имеем if
, и while
, и их друзей в C точно так, что нам не нужно писать код, который выглядит так, но этот уровень простоты и спагетти-кода - это то, что в конечном итоге завершает выполнение процессоров (и это все, что вам нужно для завершения Turing), поэтому у нас есть компилятор, чтобы превратить что-то, что выглядит более понятным и поддерживаемым для людей в виде беспорядка, с которым отлично справляются процессоры.
Если это не предназначено для можно использовать для некоторого кода для гольфа. Я не понимаю, почему вы хотите это сделать. Также я не вижу способа реализовать ветку 'else', используя какую-то конструкцию цикла while. Если ветка if-then да, но не другая. – datenwolf
if-else может быть заменен коммутатором и условными операторами. –