首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >(4 +4)不等于(子+ 4)?

(4 +4)不等于(子+ 4)?
EN

Stack Overflow用户
提问于 2015-05-13 09:42:00
回答 2查看 135关注 0票数 6

(编辑) TL;DR:我的问题是,尽管Win32 API定义的是真正的整数常量(就像platform中那样),而Win32 Win32包装器将它们定义为子类。这就导致了一行行解析的误解。

在一个一行程序中测试对Win32::MsgBox的调用时,我对以下内容感到困惑:给出MsgBox的可能参数是消息、选择按钮类型(值0..5)和消息框图标“常量”(MB_ICONSTOP,.)的标志之和。以及标题

调用perl -MWin32 -e"Win32::MsgBox world, 4+MB_ICONQUESTION, hello"将提供预期的结果

虽然看起来类似的代码perl -MWin32 -e"Win32::MsgBox world, MB_ICONQUESTION+4, hello"是错误的

首先,我认为这是因为我没有括号,但是添加一些perl -MWin32 -e"Win32::MsgBox (world, MB_ICONQUESTION+4, hello)"会产生完全相同的错误结果。

我与一位同事一起尝试用以下代码更深入地挖掘并显示传递给函数调用的参数(因为MB_xxx常量实际上是子函数)

代码语言:javascript
运行
复制
>perl -Mstrict -w -e"sub T{print $/,'called T(#'.join(',',@_).'#)'; 42 }; print $/,'results:', join ' ,', T(1), T+1, 1+T"

输出量

代码语言:javascript
运行
复制
called T(#1#)
called T(##)
called T(#1,43#)
results:42 ,42

但是我不明白为什么在传递给join()的列表中,args T+1, 1+T被解析为T(1, 43)

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-05-13 09:51:16

B::Deparse到救援:

代码语言:javascript
运行
复制
C:>perl -MO=Deparse -MWin32 -e"Win32::MsgBox world, MB_ICONQUETION+4, hello"
use Win32;
Win32::MsgBox('world', MB_ICONQUESTION(4, 'hello'));
-e syntax OK

C:>perl -MO=Deparse -MWin32 -e"Win32::MsgBox world, 4+MB_ICONQESTION, hello"
use Win32;
Win32::MsgBox('world', 4 + MB_ICONQUESTION(), 'hello');
-e syntax OK

在第一种情况下,MB_ICONQUESTION调用被认为是带有参数+4, 'hello'的函数调用。在第二种情况下,它被认为是一个没有参数的函数调用,并添加了4个参数。它似乎不是一个常数,而是一个函数。

在源代码中,我们得到了以下验证:

代码语言:javascript
运行
复制
sub MB_ICONQUESTION                     { 0x00000020 }

它是一个返回32 (二进制中的00100000,表示正在设置的位)的函数。同样,正如苏布里克所指出的,这是一个标志变量,所以不应该使用加法,而是按位逻辑和/或运算符。

在您的情况下,它只接受任何参数并忽略它们。如果你期望有一个常数,这就有点让人困惑了。

在你的实验案例中,陈述

代码语言:javascript
运行
复制
print $/,'results:', join ' ,', T(1), T+1, 1+T

被解释

代码语言:javascript
运行
复制
print $/,'results:', join ' ,', T(1), T(+1, (1+T))

因为从右到左的执行

代码语言:javascript
运行
复制
1+T = 43
T +1, 43 = 42
T(1) = 42

因为+比逗号,具有更高的优先,而一元+甚至更高。

要消除歧义,您需要使用括号来澄清优先级:

代码语言:javascript
运行
复制
print $/,'results:', join ' ,', T(1), T()+1, 1+T
#                                      ^^-- parentheses

作为一般规则,应该始终在子例程调用中使用括号。在perldoc perlsub中有4个呼叫符号:

代码语言:javascript
运行
复制
NAME(LIST);    # & is optional with parentheses.
NAME LIST;     # Parentheses optional if predeclared/imported.
&NAME(LIST);   # Circumvent prototypes.
&NAME;         # Makes current @_ visible to called subroutine.

在我看来,其中只有第一个是透明的,而另一个则有点模糊。

票数 9
EN

Stack Overflow用户

发布于 2015-05-13 09:53:37

这与您如何调用T以及perl如何解释结果有关。

如果我们偏离你的例子,我们会得到:

代码语言:javascript
运行
复制
BEGIN { $^W = 1; }
sub T {
    use strict;
    print $/, 'called T(#' . join(',', @_) . '#)';
    42;
}
use strict;
print $/, 'results:', join(' ,', T(1), T(1, 1 + T()));

这显然不是你想要的,但确实解释了为什么你会得到你想要的结果。

在您最初的示例中,我建议您考虑使用+,因为它看起来非常类似于将MB_ICONQUESTION作为标志。

所以:

代码语言:javascript
运行
复制
use strict;
use warnings;

use Win32 qw( MB_ICONQUESTION );

print MB_ICONQUESTION;

Win32::MsgBox( "world", 4 | MB_ICONQUESTION , "hello" );

代码语言:javascript
运行
复制
use strict;
use warnings;

use Win32 qw( MB_ICONQUESTION );

print MB_ICONQUESTION;

Win32::MsgBox( "world", MB_ICONQUESTION | 4 , "hello" );

产生同样的结果。

这是因为在没有括号的情况下调用子程序时的执行情况--您可以这样做:

代码语言:javascript
运行
复制
print "one", "two";

两者都被视为print的参数。Perl假设在将sub传递给它之后的参数。

+4被枚举为参数,并传递给T

代码语言:javascript
运行
复制
sub test { print @_,"\n";};

test 1;
test +1; 

如果我们不这样做,我们就会看到perl将其视为:

代码语言:javascript
运行
复制
test 1;
test 1;

因此,最终--您已经在Win32中发现了一个bug,可以通过以下方法解决:

代码语言:javascript
运行
复制
sub MB_ICONQUESTION() {0x00000020}

Win32::MsgBox "world", 4 + MB_ICONQUESTION, "hello";
Win32::MsgBox "world", MB_ICONQUESTION + 4, "hello";

或者也许:

代码语言:javascript
运行
复制
use constant MB_ICONQUESTION => 0x00000020;

或者如前所述--代码中的变通方法--不要使用+,而是使用|,这对于位标志操作将有相同的结果,但是由于运算符的优先级永远不会传递到子例程中。(当然,总是为常量指定括号)

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30211089

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档