C和Java中的逻辑差异

35

请编译并运行此 C 代码

#include <stdio.h>

int main()
{
  int a[] = {10, 20, 30, 40, 50};
  int index = 2;
  int i;

  a[index++] = index = index + 2;
  for(i = 0; i <= 4; i++)
    printf("%d\n", a[i]);
}

输出:10 20 4 40 50

现在用Java实现相同的逻辑

class Check
{

  public static void main(String[] ar)
  {
    int a[] = {10, 20, 30, 40, 50};
    int index = 2;

    a[index++] = index = index + 2;
    for(int i = 0; i <= 4; i++)
      System.out.println(a[i]);
  }
}

输出:10 20 5 40 50

为什么两种语言的输出不同,Java的输出可理解,但我无法理解C的输出。

另外,如果我们使用前缀++运算符,两种语言将得到相同的结果,为什么呢?


18
但是谁会在真正的应用程序中写出那样的代码呢? - user85421
@CarlosHeuberger 我看到你不太熟悉 c++ 标签。 - Ryan Haining
@RyanHaining 我不明白,但是这条评论是来自2010年1月8日,当时问题没有被标记为 c++。我仍然认为 a[index++] = index = index + 2 在 C、C++ 或 Java(Python?)中都不好用 - 根据评论的赞数,我相信我不是唯一一个这样认为的人 - 或者 c++ 标签意味着代码可以难以阅读(像 Code Golf 一样吗?)。而且,看看唯一的答案,即使 C 也有点 困惑... - user85421
@CarlosHeuberger 这只是个玩笑。至少一半的 [c++] 语言相关问题可以用“你为什么要写这个?”来回答。顺便说一下,这不是合法的 Python 代码。 - Ryan Haining
1个回答

64
这是因为在C语言中,a[index ++] = index = index + 2;会导致未定义行为。您可以查看这里
从链接中得知: 如果在一个完整的表达式中写入对象,则该表达式中的所有访问都必须直接涉及计算要写入的值。该规则有效地将合法表达式限制为那些明显在修改之前进行访问的表达式。例如,旧有的i=i+1是允许的,因为对i的访问用于确定i的最终值。以下代码示例是不被允许的:
 a[i] = i++

由于 i 的一个访问(a[i] 中的访问)与最终存储在 i 中的值无关(发生在 i++ 中),所以没有很好的方法定义访问是应该在递增值存储之前还是之后发生。因此,无法确定这种访问的行为,编译器也无法确定。标准声明这是未定义的行为,可移植的程序不能使用这种构造。类似于 a[i++]=i(会导致未定义行为),你的表达式也会导致未定义行为。

你的表达式也有类似的行为。

在 Java 中,这种行为是完全定义明确的。


尽管如此,a[index++] = index+2(大体上相同的结果)是否会是未定义的呢?要说实话,我得查一下标准才能确定。 - Michiel Buddingh
2
@Michiel:是的,这也会导致未定义行为,原因相同。 - Prasoon Saurav
8
非常好的回答。你能否添加一段关于Java中定义的内容?只是为了满足好奇心 :-) 很抱歉,我没有上下文信息来确定需要翻译的内容是什么,但是如果你想了解Java中的定义,我可以告诉你Java是一种面向对象编程语言,具有强类型和静态类型特征。它的基本构建块是类,通过实例化可以创建对象。Java还提供了许多预定义的类和接口,以及一个丰富的标准库,用于处理各种任务,例如输入/输出、网络通信和线程管理等。 - Topher Fangio
@Topher:paragjain的Java程序具有良好定义的行为。 - Prasoon Saurav
2
a[index++] = index+2 也是未定义行为。可以这样理解:标准规定增量在语句结束之前的某个时间发生,但没有指定除此之外的任何顺序。因此,无法确定增量是在加法之前还是之后发生。(对于 ++index 也是一样 - 虽然下标值是原始的 index + 1,但不确定何时将该值存储到 index 中。)委员会选择在标准中将其称为未定义而不是未指定,这意味着任何行为都是合法的。 - David Thornley
3
C和Java在这里有非常不同的目标。C旨在允许编译器具有提高性能的极大自由度,这适合作为系统实现语言。而Java则旨在固定所有可能的行为,以便程序员更容易编写代码。无论是C还是Java都取得了很大的成功。 - David Thornley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接