2016-07-27 12 views
1

Следующий код здесь с держать язык C Синтаксис:Вызов по потребностям и стандартным выводам C?

#include <stdio.h> 
int func(int a, int b){ 
if (b==0) 
return 0; 
else return func(a,b); 
} 

int main(){ 
printf("%d \n", func(func(1,1),func(0,0))); 
return 0; 
} 

Что вывод этого кода в 1) работать со стандартным C, 2) с любым языка, который имеет вызов необходимости собственности , Затем:

в (1) программный цикл в бесконечный вызов, а в (2) у нас есть нуль! это пример, решаемый TA в курсе программирования, любая идея для описать это для меня? благодаря

ответ

0

Для решения первой части,

: C Проект, 6.5.2.2-> 10 (вызовы функций) говорит

Порядок оценки ... фактических аргументов. .. неуточнен.

и на такой причине, что-то, такие как

printf("%d%d",i++,++i); 

имеет неопределенное поведение, потому что

  • как ++i и i++ имеет побочные эффекты, т.е. увеличивая величину I на единицу.
  • Запятая внутри printf является просто разделителем и НЕ [ sequence point ].
  • Даже если вызов функции является точкой последовательности, по указанной причине порядок, в котором не выполняются две модификации i, не определен.

В вашем случае

func(func(1,1),func(0,0)) 

хотя аргументы в пользу внешнего func т.е. func(1,1) или func(0,0) не имеют никакого отношения друг к другу в отличие от случая, показанного выше. Любой порядок оценки этих аргументов в конечном итоге приводит к бесконечной рекурсии, и поэтому программа вылетает из-за истощенной памяти.

+2

Что вы подразумеваете под «Это до процессора, чтобы выбрать порядок аргументов функции»? Почему это UB? – Xiobiq

+0

Я знаю, но почему вы думаете, что это неопределенное поведение? –

+2

Либо 'func (1,1)', либо 'func (0,0)' можно было бы оценить сначала ... но поскольку оба должны быть оценены перед внешним вызовом 'func()', он все равно даст бесконечную рекурсию (в С). – Dmitri

0

С С, в общем, не определен порядок аргументов a и b оценки с функцией, как int func(int a, int b)

Очевидно, что оценки func(1,1) является проблематичным, и код страдает от этого независимо, если func(1,1) оценивается до/после/одновременно с func(0,0)


Анализ func(a,b) в зависимости от необходимости может заключить, что если b==0 , не нужно звонить func(), а затем заменить на 0.

printf("%d \n", func(func(1,1),func(0,0))); 
// functionally then becomes 
printf("%d \n", func(func(1,1),0)); 

Applied снова и

// functionally then becomes 
printf("%d \n", 0); 

Конечно, этот вывод не уверен, как анализ b != 0 и else return func(a,b); приводит к бесконечной рекурсии. Такой код может иметь полезный желаемый побочный эффект (например, стек переполнение и сброс системы.) Таким образом, анализ, возможно, должен быть консервативными и не предположить func(1,1) будет когда-либо возвращения и не оптимизировать вне вызова, даже если он оптимизировал вызов func(0,0).


+0

Значит, вы имеете в виду, когда мы запускаем его на стандартном C из-за оценки до/после/одновременного аргумента, поведение не определено? –

+0

@ Sara PhD C не определяет верхний предел рекурсии (он может быть бесконечным (используется повторное использование фрейма стека)), только возможно как минимум минимальная сумма или рекурсия. С 'int main() {while (1); } ', у нас нет неопределенного поведения UB. Он никогда не заканчивается. Похоже, код или может/не может превышать лимит. – chux

+0

Семантически программа C будет работать бесконечно. На практике - мы не знаем. он считает неопределенное поведение? –

3

1) В C (который использует strict evaluation semantics), мы получим бесконечную рекурсию, потому что в строгих аргументов оценки оцениваются до того, как функция вызывается. Таким образом, в f(f(1,1), f(0,0))f(1,1) и f(0,0) оцениваются перед внешним f (который оценивается одним из двух аргументов, сначала не указан в C, но это не имеет значения). А так как f(1,1) вызывает бесконечную рекурсию, мы получаем бесконечную рекурсию.

2) В языке с использованием аргументов non-strict evaluation (будь то по вызову по имени или по вызову) аргументы заменяются в тело функции неоценимыми и оцениваются только тогда, когда они необходимы. Таким образом, внешний вызов f сначала вычисляются так:

if (f(0, 0) == 0) 
return 0; 
else return f(f(1,1), f(0,0)); 

Так, при оценке if, мы должны оценить f(0,0), который просто оценивает 0. Таким образом, мы идем в тогдашней ветвь if и никогда выполните else-branch. Поскольку все вызовы f используются только в ветке else, они никогда не нужны и поэтому никогда не оцениваются. Таким образом, нет рекурсии, бесконечности или иначе, и мы просто получаем 0.

+2

Почему downvote? Это правильно ... –

+1

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

+0

@EugeneSh. что вы думаете об ответе? –