Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/69.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/xpath/2.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
Java和C编译器的代码表现如何不同?_Java_C - Fatal编程技术网

Java和C编译器的代码表现如何不同?

Java和C编译器的代码表现如何不同?,java,c,Java,C,我有这段代码,我在Java和C上运行了这段代码,但它们给出了两个不同的结果。 是什么让他们跑得与众不同 x=10;y=10;z=10; y-=x--; z-=--x; x-=--x-x--; 值X的Java输出为:8,而C的输出为6 这两个编译器对于增量选项的行为如何不同?在C++中,结果是不确定的,即没有指定或保证是一致的。编译器可以自由地根据.随时做最适合的事情。 我怀疑Java[和C#等]也是如此。我不确定,但我猜这是因为Java在计算-=运算符之前,在最后一个x上计算后减量,而C++在

我有这段代码,我在Java和C上运行了这段代码,但它们给出了两个不同的结果。 是什么让他们跑得与众不同

x=10;y=10;z=10;
y-=x--;
z-=--x;
x-=--x-x--;
值X的Java输出为:8,而C的输出为6


这两个编译器对于增量选项的行为如何不同?

在C++中,结果是不确定的,即没有指定或保证是一致的。编译器可以自由地根据.

随时做最适合的事情。
我怀疑Java[和C#等]也是如此。

我不确定,但我猜这是因为Java在计算-=运算符之前,在最后一个x上计算后减量,而C++在完成表达式的其余部分之后计算-=第一和后减量。当你说这个代码被认为是C程序时,你的错误是“代码> 6 。 作为一个C程序,这是。您的编译器刚好得到6,但您也可以得到24,分段错误或编译时错误

见第6.5.2节:

在上一个序列点和下一个序列点之间,对象应有其存储值 通过表达式的评估最多修改一次。此外,先验值 应为只读,以确定要存储的值。71)

--x-x--
被本段明确禁止

编辑:

Aaron Digulla在评论中写道:

它真的没有定义吗

您是否注意到我链接到C99标准,并指出了一段说这是未定义的

gcc-Wall(GCC4.1.2)并没有对此抱怨,我怀疑任何编译器都会拒绝这段代码

该标准将某些行为描述为“未定义”,这正是因为并非所有C程序无意义的方式都能在编译时可靠地检测到。如果您认为“无警告”应该意味着一切正常,那么您应该切换到C以外的另一种语言。许多现代语言都有更好的定义。当我有选择的时候我会使用,但是还有无数其他定义良好的语言

它返回6是有原因的,您应该能够解释它

我没有注意到你解释为什么这个表达式的值为6。我希望你不要花太多时间写它,因为对我来说它返回0

Macbook:~ pascalcuoq$ cat t.c
#include <stdio.h>

int main(int argc, char **argv)
{
  int y;
  printf("argc:%d\n", argc);
  y = --argc - argc--;
  printf("y:%d\n", y);
  return 0;
}
Macbook:~ pascalcuoq$ gcc t.c
Macbook:~ pascalcuoq$ ./a.out 1 2 3 4 5 6 7 8 9
argc:10
y:0
亚伦还写道:

作为一名工程师,您应该仍然能够解释它返回一个结果或另一个结果的原因

没错!我给出了可能得到6的最简单解释:结果在C99中被明确指定为未定义的行为,在早期的标准中也是如此

以及:

最后,请展示一个编译器,它警告这个构造

据我所知,没有编译器警告
*(&x-1)
其中
x
intx。您是否声称这个构造是有效的C,并且一个好的工程师应该能够预测结果,因为没有编译器警告它?这个构造是未定义的,就像正在讨论的那个一样


最后,如果您绝对需要警告,认为存在问题,请考虑使用一个验证工具,如。它需要做出一些标准中没有的假设来捕获一些现有实践,但它正确地警告了

--x-x--
和大多数其他未定义的C行为。

那么。。。你认为哪个是正确的,你的理由是什么

我相信
x
对于前三个步骤是非常确定的

x = 10
x is decremented (its initial value is used first)
x is decremented again (its resulting value is used after)
现在
x==8
。但是看看你在这里对它做了什么(请原谅插入了人性化的空格):

这可以被编译成(如果我必须在我的语言中包含
++
--
操作符,我会这么做-副作用首先被识别出来,然后作为一个整体从语句的前后移除):

给出
x==8
的结果。或者它被编译为(语句首先被子表达式缩减):

或者子表达式可能会以另一种方式降落:

t1 = x--     // t1 = 8, x = 7
t2 = --x     // t2 = 6, x = 6
t = t2 - t1  // t = 6 - 8 = -2
x -= t       // x = 8

在这种情况下,如果没有对操作员行为的正式描述,谁能说哪一个是正确的呢?

如何评估术语?右边的
--x-x--
对Java和C的计算结果都是0,但它会改变
x
。所以问题是:
-=
是如何工作的?是否在计算右侧(RHS)之前读取
x
,然后减去RHS,还是在计算RHS之后读取。那你有吗

tmp = x // copy the value of x
x = tmp - (--x - x--) // complicated way to say x = x

在Java中,规则如下:

形式为E1 op=E2的复合赋值表达式等价于E1=(T)((E1)op(E2)),其中T是E1的类型,但E1仅计算一次。(见附件)

这意味着将复制的值,因此前后递减无效。您的C编译器可能使用不同的规则

对于C,可能有帮助:

寓意在于,在任何语言中,编写依赖于求值顺序的代码都是一种糟糕的编程实践

[编辑]Pascal Cuoq(见下文)坚持认为标准中说结果未定义。这可能是正确的:我盯着他从标准中抄出来的部分看了几分钟,不明白那句话说了什么。我想我并不是这里唯一的人:)所以我去看看我为硕士论文开发的C解释器是如何工作的。它不符合标准,但我理解它的工作原理。我猜,我是海森堡类型的人:我可以有任何一种精度,但不能两者都有;)无论如何

解析此构造时,您会得到以下解析树:

        +---- (-=) ----+
        v     -=       v
        x        +--- (-) ----+
                 v            v
              PREDEC x    POSTDEC x
该标准规定,修改
x
三次(一次在左侧,两次在两个减量操作中),会导致
x
未定义。可以但是编译器是一个确定性程序,所以当它接受一些输入时,它将
t1 = --x     // t1 = 7, x = 7
t2 = x--     // t2 = 7, x = 6
t = t1 - t2  // t = 7 - 7 = 0
x -= t       // x = 6
t1 = x--     // t1 = 8, x = 7
t2 = --x     // t2 = 6, x = 6
t = t2 - t1  // t = 6 - 8 = -2
x -= t       // x = 8
tmp = x // copy the value of x
x = tmp - (--x - x--) // complicated way to say x = x
tmp = (--x - x--) // first evaluate RHS, from left to right, which means x -= 2.
x = x - tmp // substract 0 from x
        +---- (-=) ----+
        v     -=       v
        x        +--- (-) ----+
                 v            v
              PREDEC x    POSTDEC x
#include <stdio.h>

int main() {
        int x = 8;
        x -= --x - x--;
        printf("x=%d\n", x);
}
    .loc 1 4 0
    movl    $8, -4(%rbp)    ; x = 8
    .loc 1 5 0
    subl    $1, -4(%rbp)    ; x--
    movl    $0, %eax        ; tmp = 0
    subl    %eax, -4(%rbp)  ; x -= tmp
    subl    $1, -4(%rbp)    ; x--
    .loc 1 6 0
    movl    -4(%rbp), %esi  ; push `x` into the place where printf() expects it
x -= --x - x--;