| 碧海潮生's profile碧海潮生的小屋PhotosBlogLists | Help |
|
November 22 随记一转眼,工作一年半了,代码没写过几行,感觉大多数时间用在看程序、读文档上了。
虽然也干了些实事,比如L4 support,分析feature什么的。
其实除了工作,也没啥其它需要操心的事情,但就是明显感觉人不如在学校时静得下来了,浮躁得很。
那句话怎么说来着,“一月不读书,智商输给猪”。唉,我已经一年没认真看过书了……
July 15 RHEL5 64bit下的数据类型及其转换环境: gcc 4.1.2 20080704 (Red Hat 4.1.2-44), 使用-Wall编译选项
1. 基本数据类型小结 基本类型包括字节型(char)、整型(int)和浮点型(float/double)。
定义基本类型变量时,可以使用符号属性signed、unsigned(对于char、int), 和长度属性short、long(对于int、double)对变量的取值区间和精度进行说明。 下面列举了rhel5_64bit gcc下基本类型所占位数和取值范围:
符号属性 长度属性 基本型 所占位数 取值范围 输入符举例 输出符举例
-- -- char 8 -2^7 ~ 2^7-1 %c %c、%d、%u
signed -- char 8 -2^7 ~ 2^7-1 %c %c、%d、%u unsigned -- char 8 0 ~ 2^8-1 %c %c、%d、%u [signed] short [int] 16 -2^15 ~ 2^15-1 %hd
unsigned short [int] 16 0 ~ 2^16-1 %hu、%ho、%hx [signed] -- int 32 -2^31 ~ 2^31-1 %d
unsigned -- [int] 32 0 ~ 2^32-1 %u、%o、%x [signed] long [int] 64 -2^63 ~ 2^63-1 %ld
unsigned long [int] 64 0 ~ 2^64-1 %lu、%lo、%lx [signed] long long [int] 64 -2^63 ~ 2^63-1 %lld
unsigned long long [int] 64 0 ~ 2^64-1 %llu、%llo、%llx -- -- float 32 +/- 3.40282e+038 %f、%e、%g
-- -- double 64 +/- 1.79769e+308 %lf、%le、%lg %f、%e、%g -- long double 128 +/- 1.189731e+4932 %Lf、%Le、%Lg Linux采用LP64标准,其中指针和长整数都是64位的,而普通的整数则依然是32位的:
sizeof(long) = 8 sizeof(void *) = 8 无类型的整数常量是int类型的。这可能会导致在位移时出现被截断的问题。
例如,在下面的代码中,a的最大值可以是31(在gcc下实验可知,当a>31时1<<a将进行循环移位而非截断)。 这是因为1<<a是int类型的。 long t = 1 << a; 要在64位系统上进行位移,应该使用1L,如下所示: long t = 1L << a; 在32位系统上,int和long大小相同。由于这一点,有些开发人员会交换使用这两种类型。
这可能会导致指针被赋值给int类型,或者反之。 但是在64位的系统上,将指针赋值给int类型会导致高32位的值被截断。 2. 整型提升和寻常算术转换 在64位平台上,ANSI标准中的整型提升和寻常算术转换规则依然适用,但多少显得有些令人费解.
Integral promotion
You can use a char, short, enumerated type, or bit-field, whether signed or unsigned, in any expression that calls for an integer. If an integer can hold all possible values of the original type, the value is converted to an integer; otherwise, the value is converted to an unsigned integer. 注意,整型提升的结果为int/unsigned int,而非long/unsigned long. 如:
sizeof('A') = 4 sizeof(1) = 4 sizeof(1L) = 8 即使是向printf这类可变参数函数传递整型参数时,也不会提升为long/unsigned long.
Conversion between signed and unsigned integers
When an integer with a negative sign is promoted to an unsigned integer of the same or larger type, it is first promoted to the signed equivalent of the larger type, then converted to the unsigned value. 举例而言
long n; int i = -2; unsigned k = 1; n = i + k; 1> 因为i和k的类型不一致,进行寻常算术转换
"i" is an integer with a negative sign, it is promoted to an unsigned integer of the same type (unsigned). 于是i变为一个大的正整数0xFFFFFFFE 2> 0xFFFFFFFE和k=1相加,成为0xFFFFFFFF, 类型为unsigned int. 3> 赋值运算符两侧类型不一致,进行寻常算术转换(注意!不是整型提升) 由于中间结果0xFFFFFFFF为无符号数,所以不会进行符号扩展,因此直接添0即得到最终结果 0x00000000FFFFFFFF = 4294967295 可见问题出在第1步里,只需将k强制转换为int即可:
n = i + (int)k; 这样运算的中间结果0xFFFFFFFF为有符号数,会进行符号扩展,最终结果为 0xFFFFFFFFFFFFFFFF = -1 其实整型间的算术转换令人迷惑的无非是以下四种情况:
情况 \ 平台 ILP32 LP64
int vs. unsigned int unsigned int unsigned int long vs. unsigned long unsigned long unsigned long int vs. unsigned long unsigned long unsigned long
unsigned int vs. long unsigned long long 具体说来,如果一边是无符号数另一边是有符号数, 那么若...
1> 无符号数的Rank不低于有符号数的Rank,则把有符号数转成另一边的无符号类型。
例如unsigned long和int做算术运算时都转成unsigned long,unsigned long和long做算术运算时也都转成unsigned long。 2> 无符号数的Rank低于有符号数的Rank。这时又分为两种情况,如果这个有符号数类型能够覆盖这个无符号数类型的取值范围,
则把无符号数转成另一边的有符号类型。例如LP64的平台上unsigned int和long在做算术运算时都转成long。 3> 否则,也就是这个符号数类型不足以覆盖这个无符号数类型的取值范围,则把两边都转成两者之中较高Rank的无符号类型。
例如ILP32的平台上unsigned int和long在做算术运算时都转成unsigned long。 这个规则比《C Expert Programming》里讲的简单规则准确,也容易记忆。
3. 基本类型特征及扩展数据类型 标准头文件<limits.h>定义了整型特征:
INT_MIN INT_MAX SHRT_MIN SHRT_MAX USHRT_MAX LONG_MIN LONG_MAX ULONG_MAX LLONG_MIN LLONG_MAX ULLONG_MAX 标准头文件<float.h>定义了浮点特性:
FLT_EPSILON FLT_MIN FLT_MAX DBL_EPSILON DBL_MIN DBL_MAX LDBL_EPSILON LDBL_MIN LDBL_MAX 标准(ISO C99)库中的扩展类型: <stddef.h>
typedef long unsigned int size_t; typedef long int ptrdiff_t; <signal.h>
typedef int sig_atomic_t; <time.h>
typedef long int clock_t; typedef long int time_t; <wctype.h>
typedef unsigned long int wctype_t; typedef const signed int *wctrans_t; <wchar.h>
typedef int wchar_t; typedef unsigned int wint_t; <stdint.h>
typedef signed char int8_t; typedef short int int16_t; typedef int int32_t; typedef long int int64_t; typedef unsigned char uint8_t;
typedef unsigned short int uint16_t; typedef unsigned int uint32_t; typedef unsigned long int uint64_t; typedef long int intptr_t;
typedef unsigned long int uintptr_t; POSIX库中常用的扩展类型:
typedef int pid_t;
typedef int key_t; typedef long int ssize_t; typedef long int off_t; July 11 [ZT] Top 10 reasons why Pascal is better than C1. Pascal, noble language as it is, was named after a famous French mathematician and philosopher, Blaise Pascal. C was named after a Sesame Street character.
2. Pascal's inventor, Nicholas Wirth, and parameter passing conventions coalesce to form a nifty pun: You can pronounce his name by reference: Wirth or by value: Worth. C was invented at Bell Labs, where they wouldn't know a joke from a transistor.
3. There is only one Pascal, as defined by Wirth, while C has (shall we say?) several fathers: Kernighan & Ritchie, Harbison & Steele, Barnum & Bailey, and Laurel & Hardy.
4. In C, the following variable names are all different: thesame, TheSame, theSame, and THESAME. Nuff said.
5. In Pascal, when you fool with a pointer or handle, you know you're fooling around with a pointer or handle. In C, you could be fooling around with anything. C is the ultimate language for computational promiscuity.
6. In Pascal, we *know* how big an integer is.
7. C is used by liberal, Democratic, Mike Dukakis types of programmers. Pascal is a favorite of the GOP. Hey, we know what the big language at Berkeley is, don't we?
8. C is the only language in the civilized world that still refuses to recognize the $ sign for a hexadecimal constant and continues to promote that base pretender to the throne: 0x00.
9. Pascal has well-defined rules for Scope, while C appears to be using Listerine. This accounts for the medicine breath of many C programmers.
10. In C, you can do this:
for(;P("\n").R-;P("|"))for(e=3DC;e-;P("_"+(*u++/8)%2))P("| "+(*u/4)%2);
In Pascal, you CAN'T do this :
for(;P("\n").R-;P("|"))for(e=3DC;e-;P("_"+(*u++/8)%2))P("| "+(*u/4)%2);
July 10 [ZZ]若你以柔情封起信封很有感觉的歌词~~
写一封信。
用柔软的干净的发黄的素笺。
用削得不尖不细的碳画铅笔。
时间要在秋日的傍晚。
最好是九月。
夕阳刚刚暗去。
晚风静静吹起。
要有细雨呢。
这样子。坐在紫藤花架下。先泡一壶淡茶。心思合着水气,缭缭腾开。
字是不需要写太多。
七十个字吧。
写初见的欢喜。写低眸的相思。写颦眉的暗怨。写心底的温润。
还要写这天气清凉,浮云逶迤,暗香浮动,影月黄昏。
还要写什么呢。
写一朵花,撷在手心,是一缕芬芳,还是满室馨香。
写一个人,站在这里,是站得太晚,还是等得太迟。
还是什么都不需写,对着素笺,浅笑开来。
于是哎,芳草鲜美,落英缤纷。
写吧。要从右写到左。
要从黄昏写到月夜。
然后满天星星都化做云雨,洒落下来。
迷了眼,湿了心。
和着花香水气把信封好。
那些恣意的情绪呵,便随了风,逝去吧。 July 04 难得打球今天和ZL同学打球,总共1小时,先是迟到了20分钟,然后由于体力不支,打打歇歇,总共场上时间不超过25分钟。
好久不运动,果然体力明显减退啊! T_T ZL还是一如既往的亢奋,牛~~ June 24 多普勒频移和扩展这两天抽空看了一下无线衰落信道的特性,还没弄明白.先记点东西...
Doppler spread is caused by the relative motion between the transmitter and receiver...
The spread is from fc-fd to fc+fd, fd is maximum dopper shift, and fd=fc*v/c, v is the velocity. the movement of the mobile station gives rise to a Doppler spread,
which is the width of the observed spectrum when an unmodulated carrier is transmitted. If there is only one path from the mobile to base station, the base station will observe a zero Doppler spread combined with a simple shift of the carrier frequency (Doppler frequency shift). 首先Doppler扩展发生的两个条件是:相对运动和多径,两者缺一不可。
而多径引起的时延扩展,与是否有相对运动无关,而只与多径到达的同一个频率点的相对相位有关。 对于一个单音发射信号而言,若不存在多径,只有收发端的相对运动,那么某一时刻,接收端的频率是(发射频率+多普勒频移).其中多普勒频移的大小等于(相对速度*方向角的余弦)/波长.由于收发的相对速度不断变化,因此,接收端的多普勒频移也是不断变化的,但是其变化范围总是不超过最大多普勒频移,即相对速度/波长.这种情况下,接收端在某一时刻只有一个频率,所以只能称为Doppler频移. 但是若多径和相对运动同时存在,那么发射频率经过不同路径达到接收端,接收到的频率在每条路径上都存在多普勒频移,合成的效果就是某一时刻,接收端存在多个频率,这时才能称为Doppler扩展. March 29 [ZT] 网络人士的签名-黑色幽默? :-)============================================= Ping MM:Request timed out; Ping money:Destination unreachable; Ping Love:Unkown host name; Ping Future:Reply from hell: bytes=32 time=99year TTL=1 ============================================= February 07 关于VLAN VLAN(Virtual Local Area Network)即虚拟局域网,是一种通过将局域网内的设备逻辑地而不是物理地划分成一个个网段从而实现虚拟工作组的新兴技术。IEEE于1999年颁布了用以标准化VLAN实现方案的802.1Q协议标准草案。 VLAN技术允许网络管理者将一个物理的LAN逻辑地划分成不同的广播域(或称虚拟LAN,即VLAN),每一个VLAN都包含一组有着相同需求的计算机工作站,与物理上形成的LAN有着相同的属性。但由于它是逻辑地而不是物理地划分,所以同一个VLAN内的各个工作站无须被放置在同一个物理空间里,即这些工作站不一定属于同一个物理LAN网段。一个VLAN内部的广播和单播流量都不会转发到其他VLAN中,从而有助于控制流量、减少设备投资、简化网络管理、提高网络的安全性。 VLAN是为解决以太网的广播问题和安全性而提出的一种协议,它在以太网帧的基础上增加了VLAN头,用VLAN ID把用户划分为更小的工作组,限制不同工作组间的用户二层互访,每个工作组就是一个虚拟局域网。虚拟局域网的好处是可以限制广播范围,并能够形成虚拟工作组,动态管理网络。 VLAN在交换机上的实现方法,可以大致划分为4类: 1、 基于端口划分的VLAN 这种划分VLAN的方法是根据以太网交换机的端口来划分,比如Quidway S3526的1~4端口为VLAN 10,5~17为VLAN 20,18~24为VLAN 30,当然,这些属于同一VLAN的端口可以不连续,如何配置,由管理员决定,如果有多个交换机,例如,可以指定交换机 1 的1~6端口和交换机 2 的1~4端口为同一VLAN,即同一VLAN可以跨越数个以太网交换机,根据端口划分是目前定义VLAN的最广泛的方法,IEEE 802.1Q规定了依据以太网交换机的端口来划分VLAN的国际标准。 这种划分的方法的优点是定义VLAN成员时非常简单,只要将所有的端口都指定义一下就可以了。它的缺点是如果VLAN A的用户离开了原来的端口,到了一个新的交换机的某个端口,那么就必须重新定义。 2、基于MAC地址划分VLAN 这种划分VLAN的方法是根据每个主机的MAC地址来划分,即对每个MAC地址的主机都配置他属于哪个组。这种划分VLAN的方法的最大优点就是当用户物理位置移动时,即从一个交换机换到其他的交换机时,VLAN不用重新配置,所以,可以认为这种根据MAC地址的划分方法是基于用户的VLAN,这种方法的缺点是初始化时,所有的用户都必须进行配置,如果有几百个甚至上千个用户的话,配置是非常累的。而且这种划分的方法也导致了交换机执行效率的降低,因为在每一个交换机的端口都可能存在很多个VLAN组的成员,这样就无法限制广播包了。另外,对于使用笔记本电脑的用户来说,他们的网卡可能经常更换,这样,VLAN就必须不停的配置。 3、基于网络层划分VLAN 这种划分VLAN的方法是根据每个主机的网络层地址或协议类型(如果支持多协议)划分的,虽然这种划分方法是根据网络地址,比如IP地址,但它不是路由,与网络层的路由毫无关系。它虽然查看每个数据包的IP地址,但由于不是路由,所以,没有RIP,OSPF等路由协议,而是根据生成树算法进行桥交换, 这种方法的优点是用户的物理位置改变了,不需要重新配置所属的VLAN,而且可以根据协议类型来划分VLAN,这对网络管理者来说很重要,还有,这种方法不需要附加的帧标签来识别VLAN,这样可以减少网络的通信量。 这种方法的缺点是效率低,因为检查每一个数据包的网络层地址是需要消耗处理时间的(相对于前面两种方法),一般的交换机芯片都可以自动检查网络上数据包的以太网祯头,但要让芯片能检查IP帧头,需要更高的技术,同时也更费时。当然,这与各个厂商的实现方法有关。 4、根据IP组播划分VLAN IP 组播实际上也是一种VLAN的定义,即认为一个组播组就是一个VLAN,这种划分的方法将VLAN扩大到了广域网,因此这种方法具有更大的灵活性,而且也很容易通过路由器进行扩展,当然这种方法不适合局域网,主要是效率不高。 鉴于当前业界VLAN发展的趋势,考虑到各种VLAN划分方式的优缺点,为了最大程度上地满足用户在具体使用过程中需求,减轻用户在VLAN的具体使用和维护中的工作量,Quidway S系列交换机采用根据端口来划分VLAN的方法。 关于三层交换技术假设两个使用IP协议的站点通过第三层交换机进行通信的过程,发送站点A在开始发送时,已知目的站的IP地址,但尚不知道在局域网上发送所需要的MAC地址。要采用地址解析(ARP)来确定目的站的MAC地址。发送站把自己的IP地址与目的站的IP地址比较,采用其软件中配置的子网掩码提取出网络地址来确定目的站是否与自己在同一子网内。若目的站B与发送站A在同一子网内,A广播一个ARP请求,B返回其MAC地址,A得到目的站点B的MAC地址后将这一地址缓存起来,并用此MAC地址封包转发数据,第二层交换模块查找MAC地址表确定将数据包发向目的端口。
若两个站点不在同一子网内,如发送站A要与目的站C通信,发送站A要向“缺省网关”发出ARP(地址解析)封包,而“缺省网关”的IP地址已经在系统软件中设置。这个IP 地址实际上对应第三层交换机的第三层交换模块。所以当发送站A对“缺省网关”的IP地址广播出一个ARP请求时,若第三层交换模块在以往的通信过程中已得到目的站B的MAC地址,则向发送站A回复B的MAC地址;否则第三层交换模块根据路由信息向目的站广播一个ARP请求,目的站C得到此ARP请求后向第三层交换模块回复其MAC地址,第三层交换模块保存此地址并回复给发送站A。以后,当再进行A与C之间数据包转发时,将用最终的目的站点的MAC地址封包,数据转发过程全部交给第二层交换处理,信息得以高速交换。
第三层交换的目标是,只要在源地址和目的地址之间有一条更为直接的第二层通路,就没有必要经过路由器转发数据包。第三层交换使用第三层路由协议确定传送路径,此路径可以只用一次,也可以存储起来,供以后使用。之后数据包通过一条虚电路绕过路由器快速发送。第三层交换技术的出现,解决了局域网中网段划分之后,网段中子网必须依赖路由器进行管理的局面,解决了传统路由器低速、复杂所造成的网络瓶颈问题。当然,三层交换技术并不是网络交换机与路由器的简单叠加,而是二者的有机结合,形成一个集成的、完整的解决方案。
传统的网络结构对用户应用所造成的限制,正是三层交换技术所要解决的关键问题。目前,市场上最高档路由器的最大处理能力为每秒25 万个包,而最高档交换机的最大处理能力则在每秒1000 万个包以上,二者相差40 倍。在交换网络中,尤其是大规模的交换网络,没有路由功能是不可想象的。然而路由器的处理能力又限制了交换网络的速度,这就是三层交换所要解决的问题。第三层交换机并没有象其他二层交换机那样把广播封包扩散,第三层交换机之所以叫三层交换机是因为它们能看得懂第三层的信息,如IP 地址、ARP 等。因此,三层交换机便能洞悉某广播封包目的何在,而在没有把他扩散出去的情形下,满足了发出该广播封包的人的需要,(不管他们在任何子网里)。如果认为第三层交换机就是路由器,那也应称作超高速反传统路由器,因为第三层交换机没做任何"拆打"数据封包的工作,所有路过他的封包都不会被修改并以交换的速度传到目的地。
1. 上面这段话有误,A发出去的ARP请求中没有C的IP, L3交换机怎么可能知道A想和C通信呢?交换机永远不可能用主机C的MAC来回应主机A,而是用自己的和A机所在网段的虚接口的MAC来回应。
2. 实际上三层交换的路由过程基本上靠硬件完成,当第一个包被转发后,系统会形成一个单独的转发表,后续的转发由特殊的ASIC硬件查询这个表来完成,不再走软件查询的路由过程,从而提高转发速度,这才是所谓的“一次路由,多次交换”。
3. 也就是说三层交换并没有改变数据的发送以及接收流程。所以如果把默认网关看成黑盒子,是无法判断是三层交换还是三层路由的。 October 19 理解Linux shell-bash处理因为在工作中要用到Linux shell脚本编程,我才一点一点开始学的。
纯属个人见解,错误难免,还望指正。 ^_^ 1. 基本原理 shell的重要性就不用在这里多说了。
个人感觉要理解shell的行为,首先要认识到以下几点: 1) 任何除了控制结构(while, for, if ...)和关键字以外的东西都是命令。
记住!不管是内部命令还是外部命令,命令的调用格式永远是:
cmd arg1 arg1 ... 任何参数在命令看来都是字符串(想想C里的int argc和char *argv[]) 例如
while [ $num -ge 0 ] do ... done 其中,[]实际上就是调用test命令 while test $num -ge 0 do ... done 而
if ((i%3==0)) then ... fi 中的(())实际上就是调用let命令进行表达式计算 if let "i%3==0" then ... fi 2) 命令执行的成功与否,以退出状态terminate status表示。
exit 0 返回值为0,表示成功(true)
exit 1 返回值为1,表示失败(false) 然后,控制结构再将这些true/false用于逻辑运算(&&, ||, !),控制程序的流程。
注意,&&和||的优先级是一样的。 3) 所有的命令行扩展(文件名扩展,参数扩展等)都是在将参数传递给命令前由shell完成的。
以算术赋值
((RES=1+TWO*3)) 为例,它等价于 let "RES=1+TWO*3" 也等价于 let RES=1+TWO\*3 此时let后面的东西是参数,""用于阻止记号分割及文件名扩展等。
这时,变量前可不加$。若写成let "RES=1+$TWO*3"或((RES=1+$TWO*3)), 则shell将先对$TWO进行参数扩展,然后把扩展后的结果作为参数传给let。 2. 几个要点 1) 命令替换(嵌套命令行处理)
$(ls)
等价于 `ls` $((构成一个单独的标志,它们引入算术扩展,而不是命令替换。
如果想在$()中使用一个被插入的子shell,就必须在$(和(之间插入一个空格符。 需要记住的是,算术扩展和命令替换是文本层次的替换处理。 命令替换是以其标准输出替换本身;算术扩展是以其运算结果替换本身。
2) 算术扩展
$((RES=1+TWO*3))
等效于 RES=$((1+TWO*3)) 类似(但不同)于 let "RES=1+TWO*3" 算术扩展先于文件名扩展,因此*不需要转义。
这时,变量前可不加$。但参数扩展先于算术扩展,难道shell在这种情况下作了特殊处理? 3) 条件测试
[ $num -ge 0 ]
等价于 test $num -ge 0 等效于 [[ $num >= 0 ]] [[ ]]可以看作扩展的test命令。注意,[[ ]]不进行文件名扩展和记号分隔。
而[ ]则会进行文件名扩展和记号分隔,即完全等价于test命令调用。 [[ ]]这个东东执行完以后也有返回值,就像执行test命令一样。 3. bash处理流程 前言万语不及一张图啊!
+-------------+ 单引号 |------------------------->| |--------------------------| | ----------------------->| 1.分隔成记号|--------------------| | | | ------------------->| | 双引号 | | | | | +-------------+ | | | | | || | | | | |读取下一个命令 \/ | | | | | +-------------------------------------------+ | | | | | | 2. | | | | | ------| 检验第一个记号 | | | | | |开放的关键字 其他关键字 | | | | | | 非关键字 | | | | | +-------------------------------------------+ | | | | || | | | | \/ | | | | +-----------------------------+ | | | | 扩展别名 | 3. 检验第一个记号 | | | | |------------| 别名 | | | | | 不是别名 | | | | +-----------------------------+ | | | || | | | \/ | | | +--------------+ | | | | 4.花括号扩展 | | | | +--------------+ | | | || | | | \/ | | | +--------------+ | | | | 5.代字符扩展 | | | | +--------------+ | | | || | | | \/ | | | +--------------+ 双引号 | | | | 6.参数扩展 |<-----------------| | | +--------------+ | | || | | \/ | | +------------------------------+ | | | 7|8.命令替换(嵌套命令行处理) | | | +------------------------------+ | | || | | \/ | | +--------------+ 双引号 | | | 7|8.算术扩展 |------------------| | | +--------------+ | | | || | | | \/ | | | +--------------+ | | | | 9.IFS 分词 | | | | +--------------+ | | | || | | | \/ | | | +--------------+ | | | | 10.路径名扩展| | | | +--------------+ | | | || | | | \/ | | | +----------------------------------------+ | | | | 11.命令查寻:函数,内置命令,可执行文件|<---|-----| | +----------------------------------------+ | || | \/ |将参数带入下一个命令 +-------------+ |----------eval--------------| 12.运行命令 | +-------------+ 4. 用例子说话 本节试图通过例子说明上面的bash处理流程 :-)
1) 用expr计算表达式
另一种执行算术运算的方法是调用外部命令expr,并且使用命令替换
RES=`expr 1 + $TWO \* 3` 注意,expr 3 + \( 4 \* 3 / 2 \)
等价于expr 3 + '(' 4 '*' 3 / 2 ')' 这个例子进一步说明了,跟在expr后面的那堆东东是命令行参数, 在传给命令之前会被shell动一番手脚,因此要么转义,要么用引号跳过这些处理。 使用""和''可阻止文件名扩展及shell转义。
不能在单引号里放单引号,而双引号里的单引号没有作用。
可以在双引号里包含双引号,方式是加上转义符"\"。 因为双引号允许参数替换,命令替换和算术扩展。 所以还必须转义$, `, 以及\本身。 2) 命令替换和算术扩展哪个先进行?
网上文档和《Linux命令、编辑器与Shell编程》书中顺序不一致。做如下测试:
# echo $RES 20 # echo "`echo $RES` $((--RES))" 20 19 # echo $RES 19 # echo "$((--RES)) `echo $RES`" 18 18 # echo $RES 18 似乎是同等优先级的,自左向右依次处理。 3) IFS分词有什么作用?
# VAR=hello
# "echo $VAR" -bash: echo hello: command not found 这里因为""跳过了分词,所以echo和hello不会被分解成两个部分。 于是echo hello被当作一个命令名。 function do_it()
{ "$@" } 此处是对""不分词的一个特例,用"$@"和$@是一样的,因为位置参数$@产生一串参数, 可能相当于作了IFS分词,但路径名扩展依然不会进行。因此 do_it echo $VAR 可执行。若改成"$*"则就会报错,而如果用$*也可正确执行。 4) 使用eval
但如果要执行
do_it echo $VAR \| grep hello 这样的复杂命令,就要用eval了。如eval "$@" 注意,|前必须加转义\,否则|在第一步分隔成记号时就被处理掉了,不会作为参数传给do_it。 5) 再考虑一个例子
do_it echo \* \~
若 function do_it() { $@ } 结果是 test_debug.sh test_err.sh test_hook.sh ~ 若
function do_it() { "$@" } 结果是 * ~ 很显然,""跳过了路径名扩展。 而代字符扩展在参数扩展之前,无论是否加"",都不会进行。 October 06 《嘉兴风景名胜》摘录十月四日,文炜兄造访嘉兴,于城内瓶山、子城、范蠡湖诸景稍作盘桓。 由拳县(秦)-->禾兴(三国)-->嘉兴县(赤乌五年)|-->嘉兴市秀城区
瓶山 灵光井 北丽桥 July 02 在FR里遨游昨天被某人开了十几个FR,太强悍了~
今天半天多时间是待在实验室里重现和分析。
大部分不是我们能控制的,还有一些鸡毛蒜皮的小问题。
真正的问题主要是关于光驱mount和umount的,百思不得其解。
虽然找到了解决方法但不知道为什么会有这个问题。
下午快下班的时候开始重建workshop,费劲啊。
早知道应该备份一下,不过也好,从头来过,洗心革面。就是时间紧了点。 June 27 多路有序序列归并的实现方案本文起源于去年intern时zjy和我之间的一场争论。
问题可以抽象成:有m个长度为n的有序序列,如何将它们合并成一个有序序列? zjy对他写的二分查找插入排序算法非常自信。但我坚持认为多路归并是更好的选择。
首先考虑用最简单的两路归并解决这个问题,那么时间复杂度将是:
(n+n) + (2n+n) + (3n+n) + ... + ((m-1)n+n)
= (2n+mn)(m-1) / 2 = (mn-2n+nm^2) / 2 二分查找方案最差情况下的时间复杂度是:
n*log(n) + n*log(2n) + n*log(3n) + ... + n*log((m-1)n)
= n*log(n) + n*(log(2)+log(n)) + n*(log(3)+log(n))... + n*(log(m-1)+log(n)) = n*(m-1)*log(n) + n*(log(1)+log(2)+log(3)+ ... +log(m-1)) = n*(m-1)*log(n) + n*log((m-1)!) 而多路归并的复杂度则是:
(n*m)*m
= n*m^2 如果采用最小堆,那么复杂度就可以减小为:
(n*m)*log(m)
= n*m*log(m) 可见,如果n > m,那么采用最小堆的多路归并应该是较好的选择。 反之,如果n < m,那么二分查找方案可能会表现出优势。 但是,二分查找方案的效率会随着数据的不同而产生明显的波动, 其最差情况下的复杂度将大于n*(m-1)*log(n),并且此时还未考虑数据搬移的开销; 而多路归并方案在最差的情况下的复杂度也仅仅是n*m*log(m)而已。 June 07 戏说功率谱在下姑妄言之,看客姑且听之~~ 问题也就来了,本来频谱表征了某个信号在频域上的特征,现在明明是同一个随机过程的不同实现, 很自然地,我们需要在时域上寻找一个确定的函数表征某个随机过程, 对于0均值平稳随机过程而言,这个确定的时域函数就是自相关auto_correlation(r) r=[-inf, +inf], power_spectrum(f)是一个函数,横坐标是f,也就是频率,以Hz为单位。 对于我们这些用惯了计算机的人,连续的东西似乎很难理解,也很难用MATLAB仿真。 对于一个离散随机信号序列,很容易通过样本计算得到它的自相关函数的估计。 因为FFT不可能对无限长的序列进行运算,所以必然需要对自相关函数进行截取, 为了克服这些缺陷,现代ARMA谱估计终于出场了。 最后,让我们回到功率谱曲线,换一个角度去思考。 June 05 sub-DR4庆祝酒会上周四的时候项目组开sub-DR4庆祝酒会,要求新人表演节目。
我们这组自编自演,效果竟然出奇地好,囊括了所有奖项。哈哈~~~
在下模仿赵本山卖拐,外加反串观音姐姐,还担任旁白。
得了个最佳突破奖,据说是颁发给平时和台上反差最大的人的,倒!
估计大家都没想到偶在台上会如此恶搞吧,呵呵~~
办公室边上的同事说:“没想到你上台说话的时候还挺溜的!”
偶当场就说不出话来了……
唉~~表演就是表演,平时还是不行啊,欠磨练! May 01 回家随着思绪,任意东西,在这个曾经熟悉的城市里穿行。走过每个路口的时候都会想,那里有没有留恋的人或事,是继续直行,还是进去看看。
不知不觉来到的当初住的那条街,看到了那熟悉而又陌生的红房子。到楼下的时候,踯躅再三,还是迈步上楼。 站在四楼的过道里往街对面望去,是初中时的学校。现在早已是野草横生,只有东北角的篮球场依稀可辨。
突然门栓响动,惊回首,只是物是人非。
有时按照原先的记忆却走不下去了,不是大门紧闭就是高墙阻隔。 从觉海寺边走出小巷的时候,世界突然变得喧嚣起来,走了几步又折了回来,难道我还是喜欢生活在记忆里么?
巷口一丛不知名的花开得自在,落英满地,甚是漂亮。 继续前行,想看看那户养了很多猫的人家吧,走到近前才发现房屋朽败,早已人去楼空。 走到街尽头的时候不禁想,我从此处来,该往何处去?孰料,刚往前迈了几步,城市的嘈杂早已淹没了身后的宁静。 March 23 关于Draft Meeting的相册公司做Draft Meeting的相册,用了上次去杭州时拍的一张照片。 #include <everything.h> int main(void) { |
|
|