免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2367 | 回复: 8
打印 上一主题 下一主题

$! 是只读的吗? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-09-18 15:58 |只看该作者 |倒序浏览
$! undef 总是没有起作用, 感觉 $! 变成了只读, 代码如下:
undef( $! );
print "xxx" if defined( $! );

#  总是会打印

为何呢? 我看到不少代码都有 undef $! 的用法啊...

论坛徽章:
0
2 [报告]
发表于 2009-09-18 22:23 |只看该作者
$!是perl自动会帮你设置的
就跟c库里面的errno一样,是个全局变量,你当然去可以设置errno了,但是你在调用库函数的时候,库函数也会去写这个变量

$!也是同样的道理,print函数调用的过程中也是会有错误发生,perl也是会帮你去设置$!变量的

论坛徽章:
0
3 [报告]
发表于 2009-09-19 09:17 |只看该作者
$! 的用法我一开始就在 perldoc perlvar 翻了一遍,解释确实也是这样子说的,但问题是:
print "xxx" if defined( $! );
这里,应该是 if 条件先判断啊,上下代码并未有任何函数的调用,为何会有print 或 其他函数设置 errno?

论坛徽章:
0
4 [报告]
发表于 2009-09-19 13:03 |只看该作者

回复 #3 dugu072 的帖子

一条c语言大多数情况对应了好几条汇编
一条perl语言你看似是一条,生成的中间代码有多少你知道不?

论坛徽章:
0
5 [报告]
发表于 2009-09-19 13:52 |只看该作者
确实,一条perl语句,会对应很多c的代码,甚至会有不少c库的调用,但并不是任何语句都会有c库的调用吧?
而就上面的代码而言:
undef( $! );
if( defined($!) ) {
   print "Hello\n";
}
除了第一句 undef $!之外,紧接着就是  取defined($!),除此之外就是 if 判断,而 我的疑问是 undef($!) 到底起作用没,如果它起作用了,那么唯一可能会修改 $! 的,就只有 defined() 函数,但不论从perl -f defined说明的,还是从该函数的实现来看,这里也不会有c库的调用而改变了 $!  的可能的吧?

甚至我修改代码,不要用 if 了:
undef $!;
print defined($!);
竟然还是打印的: 1,那这里的 undef( $!) ,到底起了作用没?

退一步说,如果真的如你所说,如此简单的逻辑里,都会立即改变 $! ,那么,$! 这个变量还有什么意义,它 总是在变啊,等你用的时候,早就是其他错误信息了……

所以,我还是怀疑 $! 是只读的,只有 perl 解释器在执行code时,才会根据内部调用,自己修改 $!,而对于外部程序,$! 只能只读?

[ 本帖最后由 dugu072 于 2009-9-19 13:55 编辑 ]

论坛徽章:
0
6 [报告]
发表于 2009-09-19 14:14 |只看该作者

回复 #5 dugu072 的帖子

绝对是可以改的
perlvar上也说的很清楚了
If used in a numeric context, yields the current value of errno, with all the usual caveats. (This means that you shouldn't depend on the value of $! to be anything in particular unless you've gotten a specific error return indicating a system error.) If used in a string context, yields the corresponding system error string. You can assign to $! to set errno if, for instance, you want "$!" to return the string for error n, or you want to set the exit value for the die() operator. (Mnemonic: What just went bang?)


注意其中的assign

  1. use strict;
  2. use warnings;
  3. foreach ( 1 .. 10 ) {
  4.     $! = $_;
  5.     print "###Error info for $_ is ####\n";
  6.     print $!, "\n";
  7.     print "#" x 30, " \n ";
  8. }
复制代码

你用上面的代码就可以把errno对应的错误提示都给打印一遍

loser@loserking:~$ ./a.pl
###Error info for 1 is ####
Operation not permitted
##############################
###Error info for 2 is ####
No such file or directory
##############################
###Error info for 3 is ####
No such process
##############################
###Error info for 4 is ####
Interrupted system call
##############################
###Error info for 5 is ####
Input/output error
##############################
###Error info for 6 is ####
No such device or address
##############################
###Error info for 7 is ####
Argument list too long
##############################
###Error info for 8 is ####
Exec format error
##############################
###Error info for 9 is ####
Bad file descriptor
##############################
###Error info for 10 is ####
No child processes
##############################

[ 本帖最后由 churchmice 于 2009-9-19 14:17 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2009-09-19 14:19 |只看该作者
虽然可以改,但是这个变量是不能被undef的,你undef之后perl怎么告诉你错误呢?
然后我猜所有predefined的variable都是不能被undefine的
其实undef $!只是把以前的$!变量给清空了而已,就跟errno=0一个道理
如果你进行了一个关键性的操作,这个操作可能会引起错误,需要去检查$!以进行下一步的操作,那你再操作之前就要把前面遗留下来的$!先清空掉,否则不是悲剧了?

[ 本帖最后由 churchmice 于 2009-9-19 14:58 编辑 ]

论坛徽章:
0
8 [报告]
发表于 2009-09-19 16:59 |只看该作者
原帖由 churchmice 于 2009-9-19 14:19 发表
虽然可以改,但是这个变量是不能被undef的,你undef之后perl怎么告诉你错误呢?
然后我猜所有predefined的variable都是不能被undefine的
其实undef $!只是把以前的$!变量给清空了而已,就跟errno=0一个道理
...


部分赞同, 而且经过你的的提示——“这个变量是不能被undef”,因为之前一开始就想 $! 只读与否,而没考虑undef是否对某些变量有效,于是仔细翻了下文档,做了些试验,算是搞清楚一些了:
1. $! 可以设置,但有限制,因为“You can assign a number to $! to set *errno* if ……”,这句不仅仅说明可以赋值给 $! ,而且只是说明了 可以赋值的是一个 Number
2. $! 在数字环境,表现为 error number的值;在字符串环境,表示错误string
如下代码就可以看到 $! 在error number为 1~42 区间内,存在对应的error string,尤其要注意的是对于: error number == 0 时,error string== “”;error number > 42时, error string== “Unknown error”

  1. for(0..76) {
  2.    $! = $_;
  3.    my $num = $! + 0;
  4.    print "$num. After modify: ". $! . "\n";
  5. }
复制代码

3. $! 将对其本身的赋值操作,都会转化为 Number(字符串->数字,undef->0……)后,在赋值给自己
首先第 2 点可以看到,直接赋值 number,是可以成功的,但如果赋值字符串呢?

  1. $! = 'haha';
  2. print "After modify to string: ". $! . "\n";
复制代码

  将看到 $! 为 空
修改代码为:

  1. $! = '1haha';
  2. print "After modify to string: ". $! . "\n";
复制代码

   将看到 $! 为: Operation not permitted,正式第 2 点中,$!=1时候,对应的 error string 的内容
   因此 undef( $! )的结果,实际上, 此时 $! 被赋值为 $! = 0,对应的是 "" 字符串,因此 defined( $! )是 true
4. “然后我猜所有predefined的variable都是不能被undefine的”——这句话,分析到这里,肯定就不对了,因为 undef $!; 的结果,只是 $! 本身的特性而已,对其他内部变量,没有什么参考意义。当然我也简单试验了下:

  1. print "\$\" Before modify: ". defined($") . "\n";
  2. undef $";
  3. print "Undef successfully!\n" unless defined($");
复制代码

输出结果是:
$" Before modify: 1
Undef successfully!
可以看到,undef成功了

再次感谢 churchmice 的提示, 顺便再帮我看看,分析的有什么问题没?

论坛徽章:
0
9 [报告]
发表于 2009-09-19 17:46 |只看该作者

回复 #8 dugu072 的帖子

分析的很细致
第4点经你这么一说我也想起来了,在读取整个文件(slurp模式)的时候就经常undef $/ 的
感谢你的指出,证明我的猜测还是不准确
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP