代码之家  ›  专栏  ›  技术社区  ›  Seibar

逻辑顺序和编译器行为

  •  16
  • Seibar  · 技术社区  · 17 年前

    在C,(并且可以自由回答其他语言),运行时评估逻辑语句的顺序是什么?

    例子:

    DataTable myDt = new DataTable();
    if (myDt != null && myDt.Rows.Count > 0)
    {
        //do some stuff with myDt
    }
    

    运行时首先计算哪个语句-

    myDt != null
    

    或:

    myDt.Rows.Count > 0
    

    ?

    有没有一段时间编译器会向后计算语句?可能涉及“或”运算符时?


    &被称为逻辑位运算符,将始终计算所有子表达式

    什么时候使用位运算符而不是“短路布尔”是一个很好的例子?

    18 回复  |  直到 17 年前
        1
  •  17
  •   ZombieSheep    15 年前

    C:从左到右,如果发现不匹配(计算结果为假),处理将停止。

        2
  •  9
  •   Brian Leahy    17 年前

    C:从左到右,如果找到匹配项(计算结果为真),则停止处理。

    僵尸羊是错误的,没有足够的代表投反对票。

    问题是关于&operator,而不是operator。

    如果发现错误,评估将停止。

    如果计算结果为真,则停止。

        3
  •  8
  •   OJ.    17 年前

    我知道这个问题已经被回答了,但是我想再加一点与这个主题相关的信息。

    在像C++这样的语言中,实际上你可以重载放大器和运算符的行为,强烈建议你使用。 不要这样做 . 这是因为当您超载这种行为时,最终会强制对操作的两侧进行评估。这有两件事:

    1. 它破坏了延迟评估机制,因为重载是一个必须调用的函数,因此在调用函数之前对这两个参数进行评估。
    2. 所述参数的评估顺序没有保证,可以是特定于编译器的。因此,对象的行为方式与问题/先前答案中列出的示例中的不同。

    更多信息,请阅读斯科特·梅耶斯的书, More Effective C++ . 干杯!

        4
  •  6
  •   csmba    17 年前

    运动模拟

    if( x isNot Nothing AndAlso x.go()) then
    
    1. 从左到右进行评估
    2. 而且 操作员确保只有左侧为真时,才会评估右侧(非常重要,因为if x不是什么x.go会崩溃)

    您可以使用 而不是VB中的andalso。在这种情况下,左侧也会先进行评估,而右侧则会进行评估,而不管结果如何。

    最佳实践:总是使用andalso,除非你有很好的理由不这样做。


    在后续调查中,有人问为什么或何时会有人使用Andalso而不是Andalso(或&而不是&&): 下面是一个例子:

    if ( x.init() And y.init()) then
       x.process(y)
    end 
    y.doDance()
    

    在这种情况下,我想初始化x和y。y必须初始化,y.dodance才能执行。但是,在init()函数中,我还做了一些额外的事情,比如检查一个套接字是否打开,并且只有当它正常工作时,对于 二者都 ,我应该继续做x.process(y)。

    同样,在99%的情况下,这可能是不需要的,也不优雅,这就是为什么我说默认应该使用 而且 .

        5
  •  5
  •   Orion Edwards    17 年前

    @希斯特默

    谦虚的概念指的是运算符重载。在声明中: … 首先对a进行计算,如果其计算结果为false,则从不对b进行计算。同样适用于

    这不是运算符重载。运算符重载是一个术语,用于定义运算符的自定义行为,如*、+、=等。

    这将允许您编写自己的“日志”类,然后

    a = new Log(); // Log class overloads the + operator
    a + "some string"; // Call the overloaded method - otherwise this wouldn't work because you can't normally add strings to objects.
    

    这样做

    a() || b() // be never runs if a is true
    

    实际上被称为 Short Circuit Evaluation

        6
  •  4
  •   Brad Tutterow    17 年前

    僵尸死掉了。唯一可能等待的“抓住机会”是,只有当您使用&运算符时,这才是正确的。使用&运算符时,无论一个或两个表达式的值是否为false,都将每次对这两个表达式进行计算。

    if (amHungry & whiteCastleIsNearby)
    {
       // The code will check if White Castle is nearby
       // even when I am not hungry
    }
    
    if (amHungry && whiteCastleIsNearby)
    {
       // The code will only check if White Castle is nearby
       // when I am hungry
    }
    
        7
  •  4
  •   Lasse V. Karlsen    17 年前

    请注意,&和&之间在计算表达式的多少方面存在差异。

    &&被称为短路布尔值,并且,如这里的其他人所指出的,如果在计算所有子表达式之前可以确定结果,那么将提前停止。

    &被称为逻辑位运算符,将始终计算所有子表达式。

    像这样的:

    if (a() && b())
    

    只会呼叫 如果 收益率 .

    然而,这:

    if (a() & b())
    

    将始终调用两者 ,即使调用的结果 是虚假的,因此被认为是 不管调用结果如何 .

    对于和操作符,也存在相同的差异。

        8
  •  4
  •   Mike Stone    17 年前

    有些语言有有趣的情况,即表达式以不同的顺序执行。我特别想到了Ruby,但我确信他们是从其他地方(可能是Perl)借用的。

    逻辑中的表达式将保持从左到右,但例如:

    puts message unless message.nil?
    

    上面将评估“message.nil?”首先,如果它的计算结果为假(除非它在条件为假而不是真时执行),则将执行“放置消息”,将消息变量的内容打印到屏幕上。

    有时候这是一种很有趣的方法来构造代码…我个人喜欢把它用在像上面这样很短的一行。

    编辑:

    为了更清楚一点,上述内容与以下内容相同:

    unless message.nil?
      puts message
    end
    
        9
  •  2
  •   Shawn    17 年前

    左边一个,如果为空则停止。

    编辑:在vb.net中,除非使用andalso,否则它将同时计算并可能引发错误。

        10
  •  2
  •   shsteimer    17 年前

    谦虚的概念指的是运算符重载。在声明中:

    if( A && B){
        // do something
    }
    

    首先对a进行计算,如果其计算结果为false,则从不对b进行计算。同样适用于

    if(A || B){
        //do something
    }
    

    首先计算a,如果它的计算结果为真,则从不计算b。

    这个概念,即重载,适用于(我认为)所有C风格的语言,以及许多其他语言。

        11
  •  1
  •   Vaibhav    17 年前

    不,至少C编译器不会向后工作(在&&或中)。从左到右。

        12
  •  1
  •   Orion Edwards    17 年前

    当一切都在一条直线上时,就会从左到右执行。

    当事物被嵌套时,它们是从内到外执行的。这可能像通常一样让人困惑,“最里面的”在行的右边,所以看起来好像是在倒退……

    例如

    a = Foo( 5, GetSummary( "Orion", GetAddress("Orion") ) );
    

    事情就是这样发生的:

    • 呼叫 GetAddress 用文字 "Orion"
    • 呼叫 GetSummary 用文字 猎户座 结果是 获取地址
    • 呼叫 Foo 用文字 5 结果是 获取摘要
    • 将此值赋给 a
        13
  •  1
  •   C. K. Young    17 年前

    我喜欢猎户座的反应。我将添加两个内容:

    1. 从左到右仍然首先应用
    2. 内部到外部,以确保在调用函数之前解析所有参数

    假设我们有以下示例:

    a = Foo(5, GetSummary("Orion", GetAddress("Orion")),
               GetSummary("Chris", GetAddress("Chris")));
    

    执行顺序如下:

    1. GetAddress("Orion")
    2. GetSummary("Orion", ...)
    3. GetAddress("Chris")
    4. GetSummary("Chris", ...)
    5. Foo(...)
    6. 指派给 a

    我不能谈论C的法律要求(虽然我在编写这篇文章之前使用MNO来测试一个类似的例子),但是这个命令是用Java来保证的。

    只是为了完整性(因为这也是一个语言不可知线程),有语言,如C和C++,其中的顺序不能保证,除非有一个序列点。参考文献: 1 , 2 . 然而,在回答线程的问题时, && || 是C++中的序列点(除非重载;也见OJ的优秀答案)。所以举几个例子:

    • foo() && bar()
    • foo() & bar()

    && 案例, foo() 保证运行前 bar() (如果后者完全运行),因为 && 是序列点。在 & 没有这样的保证(C和C++),确实如此。 巴尔) 可以跑之前 英尺() 反之亦然。

        14
  •  1
  •   Bruce Alderman    17 年前

    什么时候使用位运算符而不是“短路布尔”是一个很好的例子?

    假设您有标记,比如文件属性。假设您将read定义为4,write定义为2,exec定义为1。在二进制中,这是:

    READ  0100  
    WRITE 0010  
    EXEC  0001
    

    每个标志都有一个位集,并且每个位都是唯一的。位运算符允许您组合这些标志:

    flags = READ & EXEC; // value of flags is 0101
    
        15
  •  0
  •   GateKiller    17 年前

    我在某个地方听说编译器是向后工作的,但我不确定这是多么真实。

        16
  •  0
  •   Lasse V. Karlsen    17 年前

    当您特别想评估所有子表达式时,您可以使用&因为它们有您想要的副作用,即使最终结果是 因此不执行 然后 你的一部分 如果 -声明。

    请注意,&和对位掩码和布尔值都进行操作,而不仅仅是对位操作。他们是 打电话 按位,但它们都是为C中的整数和布尔数据类型定义的。

        17
  •  0
  •   Community CDub    8 年前

    @csmba :

    以下是一个例子:

    if ( x.init() And y.init()) then
       x.process(y)
    end 
    y.doDance()
    

    在这种情况下,我想初始化x和y。y必须初始化,y.dodance才能执行。但是,在init()函数中,我还做了一些额外的事情,比如检查一个套接字是否打开,并且只有当这两个都正常时,我才应该继续执行x.process(y)。

    我认为这相当令人困惑。虽然您的示例有效,但它不是使用 And (我可能会用不同的方式来写,以使它更清晰)。 ( & 在大多数其他语言中)实际上是位和操作。您可以使用它来计算位操作,例如删除标志位或屏蔽和测试标志:

    Dim x As Formatting = Formatting.Bold Or Formatting.Italic
    If (x And Formatting.Italic) = Formatting.Italic Then
        MsgBox("The text will be set in italic.")
    End If
    
        18
  •  0
  •   Community CDub    8 年前

    D编程语言可以 left-to-right evaluation with short circuiting doesn't 允许重载 && and '||' 运算符。

    推荐文章