Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/58.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 为什么在这个函数中全局变量和局部变量不同?_C_Scope_Function Call - Fatal编程技术网

C 为什么在这个函数中全局变量和局部变量不同?

C 为什么在这个函数中全局变量和局部变量不同?,c,scope,function-call,C,Scope,Function Call,在这里,我有一个名为max(a,b)的函数,用于从两个函数中获取最大值。 我发现使用printf()执行后变量a和b的值不同 printf("maxab()=%d after max: a=%d b=%d \n",max(a++,b++),a,b); 当a和b是全局变量和局部变量时。下面是我的代码: #include<stdio.h> int max(int a,int b) { if(a>b) { //printf("In func ma

在这里,我有一个名为
max(a,b)
的函数,用于从两个函数中获取最大值。 我发现使用
printf()
执行后变量
a
b
的值不同

printf("maxab()=%d after max: a=%d b=%d \n",max(a++,b++),a,b);
a
b
全局变量
局部变量
时。下面是我的代码:

#include<stdio.h>

int max(int a,int b)
{

    if(a>b)
    {
        //printf("In func max():%d %d \n",a,b);
        return a;
    }
    else {
        //printf("In func max():%d %d \n",a,b);
        return b;
    }

}
void jubu_test(void)
{
    int a=1;
    int b=2;    
    printf("maxab()=%d after max: a=%d b=%d \n",max(a++,b++),a,b);  //a=2,b=3
}
int c=2;
int d=1;
void quanju_test(void)
{
    printf("maxcd()=%d  c=%d d=%d \n",max(c++,d++),c,d);    //c=2,d=1
    c=2;
    d=1;
    int f=max(c++,d++);
    printf("maxcd()=%d after max: c=%d d=%d \n",f,c,d);     //c=3,d=2
}   
int main(int argc, char** argv)
{
    jubu_test();
    quanju_test();
}
我的问题是:为什么在第二个输出中a和b是它们的原始值,为什么第三个输出是a+1和b+1?为什么当a和b是全局变量时,打印出来的a和b的值只有在我们首先执行
max(a++,b++)
时才会改变?为什么当a和b是局部变量时,这并不重要

谢谢!
(在windows 10上使用gcc 5.3.0)

我相信,它与变量的范围无关。C没有指定函数参数求值的确切顺序。因此,这是未指定的行为。

表达式
printf(…max(a++,b++),a,b)是根据的未定义行为

a++
的求值与
a
的求值没有顺序,与
b++
b
相同。在调用函数之前有一个序列点并不重要,因为子表达式可以在该序列点之前以任何顺序求值

未定义的行为=始终是一个bug。意味着程序可以有任何类型的行为,打印任何东西,崩溃和烧录等

它是未定义行为的原因如下,C11 6.5/2:

如果标量对象上的副作用相对于 对同一标量对象或值的不同副作用 使用相同标量对象的值进行计算时,行为为 未定义

a
是标量对象,而不是数组或结构等。
a++
会导致更新变量的副作用。这与同一表达式中其他地方的
a
的值计算无关。)


不要与未指定的行为混淆,这意味着程序的行为是决定性的,但您不知道以何种方式。例如,函数参数的求值顺序是未指定的行为:

int func (void)
{
  static int x=0;
  x++;
  return x;
}

printf("%d %d", func(), func());
这可能会打印
12
21
,我们无法知道或假设哪个适用。编译器不需要记录这一点,也不必在整个程序中保持一致的行为。它可以在一种情况下选择一个订单,在另一种情况下选择另一个订单


依赖未指定行为的代码是不好的,但不会像包含未定义行为的代码那样表现得完全不稳定。

这是正确的,但在这两种情况下表现不同仍然很奇怪。根本原因是什么(即使它在各种C实现中不一致)?@jakehoffmann您必须查看汇编(我们不需要)才能确定。但这似乎毫无意义,因为代码一开始就被破坏了。@jakehoffmann-原因是编译器对代码进行静态分析,每次都以不同的顺序计算参数(可能是随机的)。它是在它的权利范围内的,为什么一个人不应该依赖于未指定的行为(因为未指定,与定义的实现不同,意味着它不必被记录)。@Jakehoffmann根本原因是让编译器可以自由地按照他们喜欢的任何顺序评估其内部表达式树,因此生成的代码会稍微快一点。这个
max(a++,b++),a,b
也是未定义的行为,因为在更新
a
时会产生副作用,在同一表达式中,该副作用与
a
不相关,并且
a
不用于确定要存储的值。请参阅@SouravGhosh,我正在努力找到答案。在我提出复制品后,我开始深入思考它。在这种情况下,递增的变量是不同的,因此不像
i++
++
++i
那样,顺便说一句,gcc在函数inc的序列点上显示了很多警告call@SouravGhosh我收回了它。顺便说一句,如果gcc实际正确地评估了它们,那么这是UB,而不仅仅是未指定。添加
-Wall-Wextra和-pedantic错误,您将看到它们
-Wall
这对于您的具体情况已经足够了。订单确实可能是
a++
->
a
->调用
max()
,这使得我之前关于序列点的评论毫无意义。最后总是会出现未定义的行为+1.
int func (void)
{
  static int x=0;
  x++;
  return x;
}

printf("%d %d", func(), func());