当前位置: 首页 > 面试题库 >

C ++和PHP与C#和Java-不相等的结果

赵英范
2023-03-14
问题内容

我在C#和Java中发现了一些奇怪的地方。让我们看一下这个C ++代码:

#include <iostream>
using namespace std;

class Simple
{
public:
    static int f()
    {
        X = X + 10;
        return 1;
    }

    static int X;
};
int Simple::X = 0;

int main() {
    Simple::X += Simple::f();
    printf("X = %d", Simple::X);
    return 0;
}

控制台中,您将看到X = 11(在此处查看结果-IdeOne C ++)。

现在让我们看一下C#上的相同代码:

class Program
{
    static int x = 0;

    static int f()
    {
        x = x + 10;
        return 1;
    }

    public static void Main()
    {
        x += f();
        System.Console.WriteLine(x);
    }
}

在控制台中,您将看到1(而不是11!)(在这里查看结果-IdeOne C#
我知道您现在在想什么-“这怎么可能?”,但让我们转到下面的代码。

Java代码:

import java.util.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
    static int X = 0;
    static int f()
    {
        X = X + 10;
        return 1;
    }
    public static void main (String[] args) throws java.lang.Exception
    {
        Formatter f = new Formatter();
        f.format("X = %d", X += f());
        System.out.println(f.toString());
    }
}

结果与C#中的结果相同(X = 1,在此处查看结果)。

最后,让我们看一下PHP代码:

<?php
class Simple
{
    public static $X = 0;

    public static function f()
    {
        self::$X = self::$X + 10;
        return 1;
    }
}

$simple = new Simple();
echo "X = " . $simple::$X += $simple::f();
?>

结果为11(在此处查看结果)。

我有一点理论-这些语言(C#和Java)在堆栈上制作静态变量X的本地副本(它们是否忽略了 static 关键字?)。这就是为什么这些语言的结果为1。

这里有人,还有其他版本吗?


问题答案:

C ++标准规定:

对于不确定顺序的函数调用,复合赋值的操作是单个评估。[注意:因此,函数调用不应介于左值到右值转换和与任何单个复合赋值运算符相关的副作用之间。—尾注]

§5.17[expr.ass]

因此,与您在同一评估中使用X并且对产生副作用的函数一样X,结果是不确定的,因为:

如果相对于相同标量对象上的另一个副作用或使用相同标量对象的值进行的值计算,相对于一个标量对象的副作用是未排序的,则该行为是不确定的。

§1.9[介绍执行]

在许多编译器上它恰好是11,但是不能保证C ++编译器不会像其他语言那样为您提供1。

如果您仍持怀疑态度,则对该标准的另一分析将得出相同的结论:该标准在上述同一部分中也表示:

形式的表达式的行为与行为E1 op = E2相同,E1 = E1 op E2只是E1它只计算一次。

在您的情况下X = X + f()X只评估一次。
由于不能保证评估的顺序X + f(),因此您不能认为先评估f然后评估X

附录

我不是Java专家,但是Java规则清楚地指定了表达式中的求值顺序,这在Java语言规范的
15.7节中保证从左到右。在 15.26.2。 Java规范还说, Compound Assignment OperatorsE1 op= E2等效E1 = (T) ((E1) op (E2))

在您的Java程序中,这再次意味着您的表达式等于X = X + f()并且首先X被求值,然后是f()。因此,结果中f()未考虑的副作用。

因此,您的Java编译器没有错误。它只是符合规格。



 类似资料:
  • 问题内容: 我知道您可以使用lock在c#中锁定对象,但是可以放弃该锁并等待其他东西来通知您它已更改,就像您可以在Java中使用wait和notify一样吗? 在我看来,分别在Java和C#中同步和锁定是同义的。 问题答案: 等效功能(包括常规锁定)在Monitor类中。 C#中的语句等效于调用并带有适当的try / finally块。 有关更多详细信息,请参见我的线程教程或Joe Albahar

  • 问题内容: 因此,在C#中,我可以将a 视为。 是否有Java等效项? 问题答案: 等于。 如果实现数组,在类型系统中将是一个奇怪的现象。是的实例,但不是。类和接口不能乘以不同的通用参数来实现相同的通用接口。 将像增强的for循环中的一样工作。 可以很容易地变成: 优先于数组而不是集合(对于非基本类型而言)。引用类型的数组有点奇怪,自Java 1.5开始很少使用。

  • 我已经开始在win32上使用C。正如我们所知,C结构与类相同,但默认为公共成员等。。。现在我想要的是简单的C结构,它没有默认的构造函数、复制或移动操作或任何其他魔法。因为我想将其存储在文件中,还可以执行memcpy,用作字节数组等。。。所以我想用#ifdef u cplusplus在标题中定义它,如下所示。 但这只能防止函数名称的混乱。但如果在cpp文件中,struct仍然编译为cpp struc

  • 我有相同的数据和加密密钥,相同的算法,相同的模式,但不同的结果。 C#代码: 结果:13A6DAD3119F29A8C4BF6D5BD11564E4E1A93F85B7F2AD9E8E97756688754DE32A23ADE41DFD9F76186D8E25E66D0DCF458ECAA026F16463811C48FC814E50B10FF57FDDB0C0761088D1AC4DDDAE74

  • 问题内容: 在C#中寻找与此方法相同的方法 问题答案: 在C#中超级简单:

  • 问题内容: 我正在尝试使用C#和Java加密相同的数据。如果数据超过7个字节,则Java和C#加密值不相同。 输入1: 一 java的输出: FrOzOp / 2Io8 = C#输出: FrOzOp / 2Io8 = 输入2: abc j: H9A / ahl8K7I = c#: H9A / ahl8K7I = 输入3: aaaaaaaa ( 问题 ) j: Gxl7e0aWPd7j6l7uIEu