这是C中未定义的行为吗?如果没有逻辑上的预测输出 [英] Is this undefined behaviour in C ? If not predict the output logically

查看:80
本文介绍了这是C中未定义的行为吗?如果没有逻辑上的预测输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

代码1

#include <stdio.h>
int f(int *a, int b) 
{
  b = b - 1;
  if(b == 0) return 1;
  else {
    *a = *a+1;

    return *a + f(a, b);
  }
}

int main() {
  int X = 5;
  printf("%d\n",f(&X, X));
}

考虑此C代码.这里的问题是预测输出.从逻辑上讲,我的输出是31. (计算机上的输出)

Consider this C code. The question here is to predict the output. Logically, I get 31 as ouput. (Output on machine)

当我将return语句更改为

When I change the return statement to

return f(a, b) + *a;

我在逻辑上是37.(计算机上的输出)

I logically get 37. (Output on machine)

我的一个朋友说,在

return *a + f(a, b);

我们计算树的深度的值,即*首先计算然后调用f(a, b)的值,而在

we compute the value of a while going depth of the tree, i.e. *a first computed then f(a, b) is called, whereas in

return f(a,b) + *a;

返回时解析,即先计算f(a, b)然后调用*a.

It is resolved while returning back, i.e. f(a, b) is computed first then *a is called.

使用这种方法,我尝试自己预测以下代码的输出:

With this approach, I tried predicting the output of the following code myself:

代码2

#include <stdio.h>
int foo(int n) 
{
    static int r;
    if(n <= 1)
        return 1;

    r = n + r;
    return r + foo(n - 2);
} 

int main () {
   printf("value : %d",foo(5));
}

对于return(r+foo(n-2));

我在逻辑上得到14作为输出(计算机上的输出)

Im getting 14 as Output Logically (Output on machine)

对于return(foo(n-2)+r);

我得到17作为输出. (计算机上的输出)

I get 17 as output. (Output on machine)

但是,当我在系统上运行代码时,两种情况下我都得到17.

However, when I run the code on my system I get 17 in both cases.

我的问题:

  • 我朋友给的方法正确吗?
  • 如果是这样,为什么在计算机上运行时为什么在代码2 中得到相同的输出?
  • 否则,解释代码1 代码2的正确方法是什么?
  • 因为C不支持通过引用传递,所以是否存在任何未定义的行为?由于它在代码1 中使用,很难使用指针来实现吗?
  • Is the approach given by my friend correct?
  • If so, why do I get the same output in Code 2 when I run in a machine?
  • If not, what is the correct way to interpret Code 1 and Code 2?
  • Is there any undefined behaviour because C does not support pass by Reference? As it is being used in Code 1 tough it can be implemented using pointers?

简而言之,我只是想知道在上述4种情况下预测输出的正确方法.

In a nutshell, I simply wanted to know the correct way to predict the output in the 4 cases mentioned above.

推荐答案

代码1

对于代码1 ,因为标准未指定return *a + f(a, b);(和return f(a, b) + *a;)中术语的评估顺序,并且该函数修改了a为指向,您的代码具有未指定的行为,并且可能有各种答案.

Code 1

For Code 1, because the order of evaluation of the terms in return *a + f(a, b); (and in return f(a, b) + *a;) is not specified by the standard and the function modifies the value that a is pointing at, your code has unspecified behaviour and various answers are possible.

正如您从评论中的愤怒中可以看出的那样,术语未定义的行为",未指定的行为"等在C标准中具有技术含义,并且该答案的早期版本在应有的地方误用了未定义的行为".使用了未指定".

As you can tell from the furor in the comments, the terms 'undefined behaviour', 'unspecified behaviour' and so on have technical meanings in the C standard, and earlier versions of this answer misused 'undefined behaviour' where it should have used 'unspecified'.

问题的标题是这是C中的未定义行为吗?",答案是否;这是未指定的行为,而不是未定义的行为".

The title of the question is "Is this undefined behaviour in C?", and the answer is "No; it is unspecified behaviour, not undefined behaviour".

对于固定的代码2 ,该函数还具有未指定的行为:静态变量r的值通过递归调用进行更改,因此对评估顺序的更改可能会更改结果.

For Code 2 as fixed, the function also has unspecified behaviour: the value of the static variable r is changed by the recursive call, so changes to the evaluation order could change the result.

对于代码2 (最初与int f(static int n) { … }一起显示),该代码不会(或至少不应)编译.函数的参数定义中唯一允许的存储类是register,因此static的出现应该给您带来编译错误.

For Code 2, as originally shown with int f(static int n) { … }, the code does not (or, at least, should not) compile. The only storage class permitted in the definition of an argument to a function is register, so the presence of static should be giving you compilation errors.

ISO/IEC 9899:2011§6.7.6.3函数声明符(包括原型) ¶2在参数声明中唯一出现的存储类说明符是register.

ISO/IEC 9899:2011 §6.7.6.3 Function declarators (including prototypes) ¶2 The only storage-class specifier that shall occur in a parameter declaration is register.

在macOS Sierra 10.12.2上使用GCC 6.3.0进行编译,如下所示(请注意,无需额外的警告):

Compiling with GCC 6.3.0 on macOS Sierra 10.12.2, like this (note, no extra warnings requested):

$ gcc -O ub17.c -o ub17
ub17.c:3:27: error: storage class specified for parameter ‘n’
 int foo(static int n)
                    ^

否;它根本不像所示那样编译-至少对于我而言,不是使用现代版本的GCC.

No; it doesn't compile at all as shown — at least, not for me using a modern version of GCC.

但是,假设该问题是固定的,该函数还具有 undefined 未指定的行为:静态变量r的值通过递归调用进行更改,因此对评估顺序的更改可能会更改结果.

However, assuming that is fixed, the function also has undefined unspecified behaviour: the value of the static variable r is changed by the recursive call, so changes to the evaluation order could change the result.

这篇关于这是C中未定义的行为吗?如果没有逻辑上的预测输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆