6、函数 1)函数 bc中的函数总是计算一个值并将其返回给调用者。函数定义是“动态的”,在输入中遇到定义之前,函数是未定义的。然后使用该定义,直到遇到相同名称的另一个定义函数。然后,新定义取代旧的定义。函数定义方式如下: define name ( parameters ) { newline auto_list statement_list } 函数的调用很简单“name(parameters)”。 2)参数 参数是数字或数组。在函数定义中,可以有0个或者多个参数,通过逗号分隔开。所有参数都是通过值参数调用的。数组是通过符号“name[]在参数定义中指定的。在函数调用中,实参是数字参数的完整表达式。相同的符号。数组的定义和传值使用相同的符号。命名数组通过值传递给函数。由于函数定义是动态的,因此在调用函数时会检查参数号和类型。参数数量或类型的不匹配都会导致运行时错误。对未定义函数的调用也会出现运行时错误。 3)auto_list “auto_list”是供“本地”使用的变量的可选列表。auto_list的语法(如果存在)是“autoname,…;”。(分号是可选的。)每个名称都是自动变量的名称。数组可以使用与参数相同的表示法来指定。这些变量的值在函数开始时被推入堆栈中。然后将变量初始化为零,并在函数的整个执行过程中使用。在函数退出时,这些变量被弹出,以便恢复这些变量的原始值(在函数调用时)。这些参数实际上是自动变量,它们被初始化为函数调用中提供的值。自动变量不同于传统局部变量,因为如果函数A调用函数B,B可以使用相同的名称访问函数A的自动变量,除非函数B调用它们为自动变量。由于自动变量和参数被推到堆栈上,bc支持递归函数。 4)函数体 函数体是一系列bc语句的列表。同样,语句用分号或换行符分隔。返回语句导致函数的终止和值的返回。返回语句有两个版本。第一个形式“return”将值0返回给调用表达式。第二种形式“return (表达式)”计算表达式的值并将该值返回给调用表达式。在每个函数的末尾有一个隐含的“return (0)”。这允许一个函数终止并返回0,而不需要显式返回语句。 函数还会改变变量ibase的用法。函数体中的所有常量都将在函数调用时使用ibase的值进行转换。在函数执行过程中,ibase的更改将被忽略,但标准函数读取除外,后者将始终使用ibase的当前值来转换数字。 当前版本的bc,在函数中添加了几个扩展。首先,定义的格式稍微放松了一些。标准要求开始大括号与定义关键字在同一行,所有其他部分必须在下面的行上。这个版本的bc将允许之前的任何数目的换行符。在函数的开头支撑之后,例如,下面的定义是合法的: define d (n) { return (2*n); } define d (n) { return (2*n); } 5)void类型 函数可以定义为void。空函数不返回值,因此可能不会在任何需要值的地方使用。空函数在输入行调用时不会产生任何输出。关键字void放在关键字定义和函数名称之间。例如,请考虑下面的例子 define py (y) { print "--->", y, "<---", "0; } define void px (x) { print "--->", x, "<---", "0; } py(1) --->1<--- 0 //由于py不是void,因此有默认返回值,因此这里打印了它的返回值, px(1) --->1<--- //px是void类型,最后不会打印返回值 此外,还为数组添加了按变量调用。为了申明一个数组变量,函数中的数组参数是这样定义的“*name[]” 。 7、数学库 1)如果使用“-l”选项调用bc,则预加载一个数学库,并将默认精度设置为20。数学库中有一下的函数:
s(x),计算x的正弦值,x是弧度值。
c(x),计算x的余弦值,x是弧度值。
a(x),计算x的反正切值,返回弧度。
l(x),计算x的自然对数。
e(x),e的x次方。
j(n,x),从n到x的阶数。 2)例子 下面的句子可以将“pi”的值赋值给shell变量pi pi = $(echo "scale=10; 4*a(1)" | bc -l) |
下面的句子就是数学库中e的次方定义方式 scale = 20 /* Uses the fact that e^x = (e^(x/2))^2 When x is small enough, we use the series: e^x = 1 + x + x^2/2! + x^3/3! + ... */ define e(x) { auto a, d, e, f, i, m, v, z /* Check the sign of x. */ if (x<0) { m = 1 x = -x } /* Precondition x. */ z = scale; scale = 4 + z + .44*x; while (x > 1) { f += 1; x /= 2; } /* Initialize the variables. */ v = 1+x a = x d = 1 for (i=2; 1; i++) { e = (a *= x) / (d *= i) if (e == 0) { if (f>0) while (f--) v = v*v; scale = z if (m) return (1/v); return (v/1); } v += e } } |
下面的语句实现一个计算支票簿余额的简单程序 scale=2 print "\nCheck book program!\n" print " Remember, deposits are negative transactions.\n" print " Exit by a 0 transaction.\n\n" print "Initial balance? "; bal = read() bal /= 1 print "\n" while (1) { "current balance = "; bal "transaction? "; trans = read() if (trans == 0) break; bal -= trans bal /= 1 } quit |
下面的语句采用递归的方式计算x的阶乘 define f (x) { if (x <= 1) return (1); return (f(x-1) * x); } |
8、readline和libedit选项 可以编译GNU bc(通过一个配置选项)来使用GNU readline输入编辑器库或bsd libedit库。这允许用户在将行发送到bc之前进行编辑。它还允许保存以前键入的行的历史记录。当选择此选项时,bc还有一个特殊变量。变量“history”是保留的历史记录行数。对于readline,值-1表示不限制历史记录的行数,0将禁用历史记录功能,默认值为100。 9、差别 这个版本的bc是从POSIX P 1003.2/D11草案中实现的,包含了与草案和传统实现相比的一些区别和扩展,它不是以传统的方式使bc(1)实现的,这个版本是一个解析和运行程序字节代码转换的单一进程。这里有一个“无文档”选项(-c),它导致程序将字节码输出到标准输出,而不是运行它。它主要用于调试解析器和准备数学库。差异的一个主要来源是扩展,下面列出一些差异和扩展: 1)LANG环境变量,此版本在处理lang环境变量和从lc_开始的所有环境变量时不符合POSIX标准。 2)名字,传统和POSIX bc都有用于函数、变量和数组的单字母名称。它们被扩展为以字母开头的多字符名称,可以包含字母、数字和下划线字符。 3)字符串,字符串不允许包含NUL字符。POSIX表示所有字符都必须包含在字符串中。 4)last,POSIX bc中没有last变量。 5)比较,POSIX bc只允许在if语句、while语句和for语句的第二个表达式中进行比较。 6)if语句,POSIX bc中if语句没有else。 7)for语句,POIX bc中要求for语句中的3个表达式都必须具备。 8)&&,||,!,POSIX bc中没有逻辑运算。 9)read,POSIX bc没有read功能。 10)打印语句,POSIX bc没有打印语句。 11)continue语句,POSIX bc没有continue语句。 12)return,POSIX bc要求return的表达式加括号。 13)数组参数,POSIX bc不(目前)完全支持数组参数。POSIX语法允许函数定义中的数组,但没有提供将数组指定为实际参数的方法。(这很可能是语法上的疏忽。)传统的bc实现只通过值数组参数进行调用。 14)函数,POSIX bc要求函数开头的大括号和define关键字在同一行,语句在下一行。 15)=+, =-, =*, =/, =%, =^。POSIX bc不要求定义这些“旧样式”赋值操作符。此版本可能允许这些“旧样式”赋值。使用限制语句查看安装的版本是否支持它们。如果它确实支持“旧样式”赋值运算符,则“a=-1”语句将使a减少1,而不是将a设置为值-1。 16)数字中的空格,bc的其他实现允许数字空格。例如,“x=1 3”将值13赋值给变量x。相同的语句将导致bc版本中的语法错误。 17)错误和执行,在程序中发现语法和其他错误时,此实现与其他实现的代码不同。如果在函数定义中发现语法错误,则错误恢复机制将尝试查找语句的开头并继续解析函数。一旦在函数中发现语法错误,该函数将不可调用并变为未定义。交互执行代码中的语法错误将使当前执行块失效。执行块由在完整语句序列之后出现的行尾终止。例如 a = 1 b = 2 这个语句有两个执行块,而下面的语句 {a = 1 b = 2} 只有一个执行块。任何运行时错误都会终止当前的执行块,而警告则不会。 18)中断,在交互会话期间,SIGINT信号(通常由终端上的“ctrl+c“生成)将导致当前执行块的执行中断。它将显示一个“运行时”错误,指示哪个功能被中断。在所有运行时结构被清除后,将打印一条消息通知用户bc准备好接收更多的输入。所有先前定义的函数都保留定义,所有非自动变量的值是中断点的值。在清理过程中,所有自动变量和函数参数都会被移除。对于一个非交互式会话,SIGINT信号将终止bc的整个运行。 10、限制 下面列出当前bc程序的一些限制,有一些限制可能已经被用户修改过。 1)BC_BASE_MAX,最大输出基设置为999。最大输入基为16。 2)BC_DIM_MAX,这是当前分布的65535以内的任意限制,每个机器可能都不一样。 3)BC_SCALE_MAX,小数点前后的位数都由INT_MAX限制。 4)BC_STRING_MAX,字符串中的字符字数由INT_MAX限制。 5)exponent,指数运算中的指数值由LONG_MAX限制。 6)variable names,当前对每个简单变量、数组和函数名字的限制32767。 11、环境变量 下面的环境变量由bc程序来控制 1)POSIXLY_CORRECT,和“-s”选项一样。 2)BC_ENV_ARGS,这是另一种获取bc参数的机制。格式与命令行参数相同。这些参数是先处理的,因此环境参数中列出的任何文件在任何命令行参数文件之前都会被处理。这允许用户设置“标准”选项和文件,以便在每次调用环境变量中的文件通常包含用户希望在每次运行bc时定义的函数定义。 3)BC_LINE_LENGTH,这应该是一个整数,指定数字输出行中的字符数。这包括用于长数字的反斜杠和换行符。,如果值是0,将禁用多行功能。此变量的任何其他值如果小于3,则将行长设置为70。 12、实例 1)简单计算 [root@192 ~]# bc bc 1.06.95 //欢迎语句 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. 12+23 //输入加法表达式,回车 35 //得到结果 100/25 //输入除法表达式,回车 4 //得到结果 quit //退出指令 [root@192 ~]# |
2)执行for循环语句 for(i=0; i<3; i++){print "hello\n"} //这是一个打印语句 hello hello hello |
3)从文件读取内容并且执行bc [root@localhost /]# cat test.c //查看文件的内容,里面全是bc语句 /*define 3 functions add,sub,mul*/ define add(x,y){ return x+y; } define sub(x,y){ return x-y; } define mul(x,y){ return x*y; } /*for statement*/ for(i=0;i<3;i++){ print "bc test ",i,"\n"; } /*print statement*/ print "10+5=",add(10,5),"\n" print "10-5=",sub(10,5),"\n" print "10&5=",mul(10,5),"\n" /*quit bc program*/ quit [root@localhost /]# bc test.c //bc程序从文件获取到代码,然后执行 bc 1.06.95 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. bc test 0 bc test 1 bc test 2 10+5=15 10-5=5 10&5=50 |
|