Programming

通过http快速共享文件

一直有这么个想法,可以通过http像nfs那样快速共享文件。用apache吧,不至于动用那个大家伙,用C写一个吧,太麻烦。最后决定用Perl写,可无意间发现了Python有个更简单的模块——SimpleHTTPServer,于是就用Python写,几行就搞定了。

代码见下:

[python]

!/usr/bin/env python

import sys
import string
import SimpleHTTPServer
import SocketServer

if len(sys.argv) != 3:
sys.exit(1)

addr = sys.argv[1]
port = string.atoi(sys.argv[2])

handler = SimpleHTTPServer.SimpleHTTPRequestHandler
httpd = SocketServer.TCPServer((addr, port), handler)
print “HTTP server is at: “, addr, port
httpd.serve_forever()

[/python]

C++标准函数查询

man page只能查Linux系统调用,C标准函数和其它一些glibc函数,不能查C++标准库函数。怎么才能像man那样查询C++的函数呢?我写了下面这么个Perl脚本来完成。

用法:

$ ./mancpp cmath::sin
$ ./mancpp cmath::cos
$ ./mancpp vector::size
$ ./mancpp algorithm::count_if

代码:

[perl]

!/usr/bin/perl

use strict;
use warnings;
use LWP::Simple;

die “Please provide one argument.n” unless @ARGV==1;
die “Use class::function format.n” unless $ARGV[0] =~ /S::S/;

my ($class, $func) = split(/::/, $ARGV[0]);
my $file = “/tmp/$class.$func.html”;

if ( ! -f “$file”) {
my $url;

if ($class =~ /^c/) {
    $url = "http://www.cplusplus.com/reference/clibrary/$class"."/".$func.".html";
} elsif ($class eq "filebuf" || $class eq "fstream"
    || $class eq "ifstream" || $class eq "ios"
    || $class eq "iostream" || $class eq "ios_base"
    || $class eq "istream" || $class eq "istringstream"
    || $class eq "ofstream" || $class eq "ostream"
    || $class eq "ostringstream" || $class eq "streambuf"
    || $class eq "stringbuf" || $class eq "stringstream"){
    $url = "http://www.cplusplus.com/reference/iostream/$class"."/".$func.".html";
} elsif($class eq "vector" || $class eq "bitset" || $class eq "deque"
    || $class eq "list" || $class eq "stack" || $class eq "map"
    || $class eq "queue" || $class eq "set" || $class eq "multiset"
    || $class eq "priority_queue" || $class eq "multimap") {
    $url = "http://www.cplusplus.com/reference/stl/$class"."/".$func.".html";
} elsif ($class eq "functional" || $class eq "iterator"
    || $class eq "memory" || $class eq "utility") {
    $url = "http://www.cplusplus.com/reference/misc/$class"."/".$func.".html";
} elsif ($class eq "algorithm") {
    $url = "http://www.cplusplus.com/reference/$class"."/".$func.".html";
} elsif ($class eq "string") {
    $url = "http://www.cplusplus.com/reference/string/$class"."/".$func.".html";
}

print "Retrieving $url", "...n";
LWP::Simple::getstore($url, "$file");

}

open my $fd, “$file” or die “No such class or function!n”;
my $found = 0;
my @ret;

while(){
if (m//) {
$found = 1;
}
if ($found) {
s/]*>//g;
s//g;
s/</</g;
s/Parameters/n==Parameters==/;
s/Example/n==Example==/;
s/See also/n==See also==/;
push @ret, $_;
}
if (m/SuOptions()/) {
$found = 0;
pop @ret;
}
}

open my $hd, "|less" or die "Can't open pipe!n";

foreach (@ret){
print $hd $_;
}

close $hd;

close $fd;
exit 0;

[/perl]

谁都没错?

$ cat abs.cpp

include <cstdlib>

include <iostream>

using namespace std;

int main()
{
cout<<abs(-19.50)<<endl;
return 0;
}

编译你会得到如下错误:

abs.cpp: In function ‘int main()’:
abs.cpp:7: error: call of overloaded ‘abs(double)’ is ambiguous
/usr/include/stdlib.h:699: note: candidates are: int abs(int)
/usr/lib/gcc/i386-redhat-linux/4.3.0/../../../../include/c++/4.3.0/cstdlib:175: note: long long int __gnu_cxx::abs(long long int)
/usr/lib/gcc/i386-redhat-linux/4.3.0/../../../../include/c++/4.3.0/cstdlib:144: note: long int std::abs(long int)

为啥呢?因为abs()在<cmath>中,而不是C++标准参考手册中提到的<cstdlib>!

谁错了捏?其实谁都没错。这里解释到:

The Standard C++ library is supposed to
overload abs the way you expect, but it’s common for implementations
to omit the overloads, or put them in the wrong place (<cmath> instead
of <math.h>).
这个真的让人很无语,一边是出错,另一边是明知道出错也这么做。。。冏。。。

gcc 4.3 改变了 -Wconversion

gcc 4.3之前,-Wconversion是这样的:

Warn if a prototype causes a type conversion that is different from what would
happen to the same argument in the absence of a prototype.

Also, warn if a negative integer constant expression is implicitly converted to
an unsigned type.
到了4.3就变了,发布日志上解释到:
The -Wconversion option has been modified. Its purpose now is to warn for
implicit conversions that may alter a value. This new behavior is available for
both C and C++. Warnings about conversions between signed and unsigned integers
can be disabled by using -Wno-sign-conversion. In C++, they are disabled by
default unless -Wsign-conversion is explicitly requested. The old behavior of
-Wconversion, that is, warn for prototypes causing a type conversion that is
different from what would happen to the same argument in the absence of a
prototype, has been moved to a new option -Wtraditional-conversion, which is
only available for C

这个改变其实挺大的,下面通过这个程序就可以展示这个问题:

[c]
void foo(short i);

void foo(short i)
{
i++; //dummy
}

int main(void)
{
int a = 1;
short b =2;
b = a;
foo(a);
return 0;
}
[/c]

$ gcc -Wall -Wtraditional-conversion -o conv conv.c
conv.c: In function ‘main’:
conv.c:14: warning: passing argument 1 of ‘foo’ with different width due to prototype
$ gcc -Wall -o conv conv.c
$ gcc -Wall -Wconversion -o conv conv.c
conv.c: In function ‘main’:
conv.c:13: warning: conversion to ‘short int’ from ‘int’ may alter its value
conv.c:14: warning: conversion to ‘short int’ from ‘int’ may alter its value

Make pthread suck less

pthread的API一直让我感到头疼,种类多而且名字又长,今天下决心把它们理清楚。

仅从名字上来看,pthread的API可以分为这么几类:

pthread_XXX:
此类API一般是对thread本身进行管理的。共包括如下API:

pthread_atfork()
pthread_create()
pthread_exit()
pthread_cancel()
pthread_join()
pthread_once()
pthread_self()
pthread_equal()
pthread_kill()
pthread_detach()
pthread_yeild()
pthread_sigmask()
pthread_key_create()
pthread_key_delete()
pthread_cleanup_push()
pthread_cleanup_pop()
pthread_testcancel()

它还可以分出两个子类,包括pthread_setWWW和pthread_getWWW,其中有:

pthread_getconcurrency()
pthread_getcpuclockid()
pthread_getschedparam()
pthread_getspecific()

pthread_setcancelstate()
pthread_setconcurrency()
pthread_setschedparam()
pthread_setschedprio()
pthread_setspecific()

pthread_attr_YYY:
YYY一般包括:init, destory, setZZZ, getZZZ。此类API是对thread本身的属性进行管理的。共包括如下API:

pthread_attr_destroy()
pthread_attr_getinheritsched()
pthread_attr_getschedparam()
pthread_attr_getschedpolicy()
pthread_attr_getscope()
pthread_attr_getstackaddr()
pthread_attr_getstack()
pthread_attr_init()
pthread_attr_setdetachstate()
pthread_attr_setguardsize()
pthread_attr_setinheritsched()
pthread_attr_setschedparam()
pthread_attr_setschedpolicy()
pthread_attr_setscope()
pthread_attr_setstackaddr()
pthread_attr_setstack()
pthread_attr_setstacksize()

pthread_MMM_XXX:
XXX一般是上面和那个XXX集合类似的操作,但MMM一般是thread的一个工具,比如:mutex,cond等。此类API是对thread的MMM工具进行操作。共包括如下API:

mutex类:
pthread_mutex_init()
pthread_mutex_destroy()
pthread_mutex_lock()
pthread_mutex_unlock()
pthread_mutex_trylock()
pthread_mutex_setprioceiling()
pthread_mutex_getprioceiling()

cond类:
pthread_cond_init()
pthread_cond_destroy()
pthread_cond_signal()
pthread_cond_broadcast()
pthread_cond_wait()
pthread_cond_timedwait()

rwlock类:
pthread_rwlock_destroy()
pthread_rwlock_init()
pthread_rwlock_rdlock()
pthread_rwlock_timedrdlock()
pthread_rwlock_timedwrlock()
pthread_rwlock_tryrdlock()
pthread_rwlock_trywrlock()
pthread_rwlock_unlock()
pthread_rwlock_wrlock()

spin类:
pthread_spin_destroy()
pthread_spin_init()
pthread_spin_lock()
pthread_spin_trylock()
pthread_spin_unlock()

barrier类:
pthread_barrier_destroy()
pthread_barrier_init()
pthread_barrier_wait()

pthread_MMMattr_YYY:
MMM和YYY同上(spin除外),此类API是对MMM工具的属性进行操作。和上面有着密切的关系。共包括如下API:

mutex类:
pthread_mutexattr_destroy()
pthread_mutexattr_getprioceiling()
pthread_mutexattr_getprotocol()
pthread_mutexattr_getpshared()
pthread_mutexattr_gettype()
pthread_mutexattr_init()
pthread_mutexattr_setprioceiling()
pthread_mutexattr_setprotocol()
pthread_mutexattr_setpshared()
pthread_mutexattr_settype()

cond类:
pthread_condattr_destroy()
pthread_condattr_getclock()
pthread_condattr_getpshared()
pthread_condattr_init()
pthread_condattr_setclock()
pthread_condattr_setpshared()

rwlock类:
pthread_rwlockattr_destroy()
pthread_rwlockattr_getpshared()
pthread_rwlockattr_init()
pthread_rwlockattr_setpshared()

barrier类:
pthread_barrierattr_destroy()
pthread_barrierattr_getpshared()
pthread_barrierattr_init()
pthread_barrierattr_setpshared()

这还没完,还有N多的新类型,比如pthread_t,pthread_attr_t,pthread_once_t,以及随之而来的宏。。。我在这就不总结了。

最后,介绍pthread的书籍有:

“PThreads Primer”. Lewis, Bill and Daniel J. Berg. California: Prentice Hall.
“Pthreads Programming”. B. Nichols et al. O’Reilly and Associates.
“Programming With POSIX Threads”. D. Butenhof. Addison Wesley
“Programming With Threads”. S. Kleiman et al. Prentice Hall

查询SNMP OID的程序

网上有个查询的网站,可惜什么结果都查不出来!靠!我实在看不下去了,动手写一个python程序来搞定,不过仍有局限性,那就是只能查询.iso.org子树。。。啥也不说了,上代码!

[python]

!/usr/bin/env python

import os,sys
import string
import re
import urllib2

if name == ‘main‘:

if len(sys.argv) != 2:
    sys.stderr.write("Please provide one OID number or string to lookup.n");
    sys.exit(1)

flag = 0
found = False

r = re.compile('^[0-9\.]+$')
if r.match(sys.argv[1]):
    r = re.compile('^1\.3')
    if r.match(sys.argv[1]):
        flag = 1
    else:
        sys.stderr.write("Please provide the full OID number under .iso.org!n")
        sys.exit(1)

try:
    req = urllib2.Request('http://www.kix.in/plan9/mirror/sources/contrib/gabidiaz/root/lib/ndb/snmp')
    resp = urllib2.urlopen(req)
    oid = resp.readline()
    name = resp.readline()
    while oid and name:
        if flag == 1:
            if oid.find(sys.argv[1]) != -1:
                print name
                found = True
                break
        else:
            n = name.lower().find(sys.argv[1].lower())
            if n != -1:
                print oid
                found = True
                if n+len(sys.argv[1]) &lt; len(name)-1:
                    print name
        oid = resp.readline()
        name = resp.readline()
    if not found:
        print &quot;Not found!&quot;
    sys.exit(0)
except IOError:
    sys.stderr.write(&quot;Probably you don&#039;t have Internet.n&quot;)
    sys.exit(1)

[/python]

ASN.1 octet string转化小脚本

可参考ASN.1关于octet string的介绍。

[bash]

!/bin/bash

i=1;
while(($i<=${#1}))
do
printf "%d" "'$(expr substr $1 $i 1)"
if (($i != ${#1}))
then
echo -n '.'
fi
i=$((i+1))
done
echo
exit 0
[/bash]

上面使用了一个鲜为人知的小技巧,而且不仔细看也不太容易察觉。

此脚本可以这么用(假设此脚本被存为to_string.sh):

$ snmpwalk -v2c -c test 192.168.90.72 .1.3.6.1.4.1.8072.1.3.2.4.1.2.${#STRING}.$(./to_string.sh $STRING).1

又见汇编技巧

在 arch/x86/include/asm/uaccess.h 中有这么一段代码:

define __range_not_ok(addr, size)

({
unsigned long flag, roksum;
__chk_user_ptr(addr);
asm(“add %3,%1 ; sbb %0,%0 ; cmp %1,%4 ; sbb $0,%0”
: “=&r” (flag), “=r” (roksum)
: “1” (addr), “g” ((long)(size)),
“rm” (current_thread_info()->addr_limit.seg));
flag;
})

这段汇编写得很有技巧性,充分利用了sbb指令carry flag,值得你仔细体会一番。还有一个关于sbb的技巧:

sbb eax,eax
sbb eax,0FFFFFFFFh

整数除法

C似乎没多少疑问,不过当有负数时还是需要特别注意的,因为标准要求是要向0对齐的。所以-5/2会是-2而不是-3。

6.5.5

When integers are divided, the result of the / operator is the algebraic quotient
with any fractional part discarded [Footnote].

Footnote: This is often called “truncation toward zero”
在C89的时候,这个问题还是交由编译器决定的。C99加强了这一点。C为什么会选择这一点?其实原因很简单,因为这么做节省时间:直接舍去小数部分。

Python在这一点上和C不同,因为它还保留了一个int(),这个和C在取整方向上是一致的:Python中的整数除法向负无穷对齐;而int()才是向0对齐的。见PEP238

Note that classic division (and floor division) round towards negative infinity,
while int() rounds towards zero, giving different answers for negative numbers.
不要被迷惑了,在Python里int(-5/2)依旧是-3而不是-2,你知道为什么。:-) 在PEP 238中,Python引入了一个新的运算符://,它始终会向下截取除法的结果(数学上的取整,英文谓之floor),看下面的例子:

>>> -5//2
-3
>>> -5.1/2.0
-2.5499999999999998
>>> -5.1//2.0
-3.0

Perl更不同,它只能通过int()来进行取整,因为普通除法在Perl里得到的结果是浮点数。《Programming Perl》中提到:

You should not use this function for generic rounding, because it truncates towards 0 and because machine representations of floating-point numbers can sometimes produce counterintuitive results.
所以这个也是向0对齐的。

再看ruby,这个似乎很简单,一律是向负无穷对齐的:

$ ruby -e ‘puts -5/2; puts -5.div(2); puts Kernel.Integer(-5/2);’

-3
-3
-3

Bash和C一致:

$ echo $[5/2] && echo $[-5/2]
2
-2

Java似乎也和C一致,不过我未验证。:-)

这里还有一个问题值得思考:为什么这些编程语言要把整数除法和浮点数除法区别对待?对于C,这个问题很简单,因为很久很久以前C并没有浮点数,只有整数,而其它语言似乎是因为受到了这一影响,当然Perl例外。不过,在很多情况下整数除法已经够用,无须打扰浮点数。