星期二, 一月 22, 2008

C static && dynamic library

首先看如下几个 C 源文件:
roc@ulfs:~/c$ cat main.c
#include
// #include "mod1.h"

void main() {
printf("Hello world: %d\n", func(8));
return;
}

roc@ulfs:~/c$ cat mod1.h
#include
// #include "mod2.c"
#include "mod2.h"

roc@ulfs:~/c$ cat mod2.h
int func(int i);

roc@ulfs:~/c$ cat mod2.c
#include

int func(int i) {
int I = i*i;
printf("i == %d\n", i);
return I;
}
然后进行编译并运行:
roc@ulfs:~/c$ gcc main.c mod2.c
roc@ulfs:~/c$ gcc main.c mod2.c
main.c: In function 'main':
main.c:4: warning: return type of 'main' is not 'int'
roc@ulfs:~/c$ ./a.out
i == 8
Hello world: 64
此时完全不需要头文件,编译器直接链接了。那么究竟何时需要头文件呢?

是不是和动态连接库有关呢?首先了解一下动态链接库:
roc@ulfs:~/c$ gcc -c main.c
roc@ulfs:~/c$ gcc -c mod2.c
roc@ulfs:~/c$ gcc -shared -o libmod2.so mod2.o
roc@ulfs:~/c$ gcc -shared -o libmod2.so.1 mod2.c
roc@ulfs:~/c$ diff libmod2.so libmod2.so.1
// 显示两个文件是完全一样的
roc@ulfs:~/c$ file libmod2.so
libmod2.so: ELF 32-bit LSB shared object, Intel 80386, version 1 (SYSV), not stripped
roc@ulfs:~/c$ file mod2.o
mod2.o: ELF 32-bit LSB relocatable, Intel 80386, version 1 (SYSV), not stripped
// 此时是两种不同的文件
然后尝试用两种方式编译:
roc@ulfs:~/c$ gcc -o dynamic.out main.o libmod2.so
roc@ulfs:~/c$ gcc -o dynamic.out.1 main.c libmod2.so
main.c: In function 'main':
main.c:4: warning: return type of 'main' is not 'int'
roc@ulfs:~/c$ diff dynamic.out dynamic.out.1
// 两个文件也是一样的
然后运行:
roc@ulfs:~/c$ ./dynamic.out
./dynamic.out: error while loading shared libraries: libmod2.so: cannot open shared object file: No such file or directory
roc@ulfs:~/c$ sudo vi /etc/ld.so.conf
...
/home/roc/c
# ADD THIS LINE
# 以确保运行时可以找到这个共享库,应该也可以使用 LD_LIBRARY_PATH 环境变量
roc@ulfs:~/c$ sudo ldconfig
roc@ulfs:~/c$ ./dynamic.out
i == 8
Hello world: 64
// 可以正确运行
// 此时仍然不需要使用头文件


# ******
roc@ulfs:~/c$ gcc -static -o static.out main.o libmod2.so
/usr/bin/ld: attempted static link of dynamic object `libmod2.so'
collect2: ld returned 1 exit status

# ****** ???

如果我不使用 libmod2.so 文件名,而使用 mod2.so 文件名会如何呢?
roc@ulfs:~/c$ gcc -shared -o mod2.so mod2.o
roc@ulfs:~/c$ diff mod2.so libmod2.so
roc@ulfs:~/c$ gcc -o dy.out main.o mod2.so
roc@ulfs:~/c$ ./dy.out
./dy.out: error while loading shared libraries: mod2.so: cannot open shared object file: No such file or directory
roc@ulfs:~/c$ LD_LIBRARY_PATH=. ./dy.out
i == 8
Hello world: 64
使用 libmod2.so 这种形式的文件名是为了在 gcc 上使用 -l 参数时更方便,能够直接找到相关的库而不需要指定具体的文件:

roc@ulfs:~/c$ gcc -o dynamic.out main.o -lmod2
/usr/bin/ld: cannot find -lmod2
collect2: ld returned 1 exit status
roc@ulfs:~/c$ gcc -o dynamic.out main.o -L. -lmod2
# 或者:
roc@ulfs:~/c$ LIBRARY_PATH=. gcc -o dynamic.out main.o -lmod2
使用 -L 或 LIBRARY_PATH 是为了保证在编译的时候能够找到需要的共享库文件。

到目前为止,没有看到必须要使用头文件的地方!

另外,可以了解一下 lib*.a 文件,它实际上是(archive)的简写,和 tar 文件非常类似,不过 tar 最初是使用磁带的,而 ar 直接将磁盘上的 *.o 对象文件打包到 *.a 档案文件中,因此可以供静态链接使用。可以用 ar -t 命令查看一个 *.la 文件。

gcc -o dynamic.out main.c libmod2.a ??????

星期二, 一月 08, 2008

Python bound/unbound methods

python class methods identity 中讨论过 instances 的 attributes/methods 的内存使用的问题,关于这一点,有另外一个说法,就是 Python 的 bound/unbound methods。

instances 的 methods 都是 bound methods,这些 methods 只有在实际调用这个方法的时候才会创建具体的 method 对象,执行结束后就会 destroy。从 python-list 上得到的回复是,虽然两个 id() 给出的值是一样的,但那只不过是一个误解,因为在前一个 instance 的 method 调用结束后,后一个 instance 的 method 会重复利用这段内存,结果造成 id() 的返回值一样。而在前面的讨论中,我们已经知道 is 是利用 im_self 来查看标识的,所以 is 测试返回 False。

一个 iptables 的奇怪需求和 TCP/IP netmask 问题

前几天 xuni 说能不能设置 iptables 控制某个网段,比如 192.168.0.10-100 的 IP 禁止掉,因为如果一个一个去增加,似乎效率太低,无论是对人还是对机器来说。

但似乎不太容易实现,首先是如何划分网段,另外这样划分和实际的网段设置(192.168.0.0/24)不同,是不是能够有效,特别是,中间作为网络地址和广播地址的 IP 能否生效?

首先解决第二个问题。随便找个计算子网及其掩码的工具,可以得到划分子网的网络地址和掩码,例如:192.168.0.96/255.255.255.224,也就是 192.168.0.96/28,则主机 IP 范围是 192.168.0.97-126,广播地址是 192.168.0.127,因为我自己的主机是 192.168.0.125,在这个网段之内。我在 iptables 中禁掉这个网段,发现有效,所以虽然网络配置是 192.168.0.0/24,但 iptables 并不受此影响。

再查看边界,将自己的 IP 改为 192.168.0.96 和 192.168.0.127,发现都可以有效的被禁止,所以不存在空洞的问题。

know IP/netmask, ask for net address 中讨论过从 IP/netmask 计算网络地址的问题,但这里第一个问题涉及到划分子网段时能否使用向 192.168.0.96/255.255.255.249 这样的掩码。这比较难于理解,所以考虑一个比较极端的例子,在《TCP/IP 详解 卷一 协议》中关于 TCP/IP 有一个这样的习题,即 255.255.0.255 这样的子网掩码是否合法。

答案是合法的,不过不符合习惯,因为难于理解,最主要的问题是其主机地址被分割在不连续的空间中了。例如:192.168.0.2/255.255.0.255,其结果是主机地址的范围是:192.168.[1-254].2。

所以如果按照习惯用法分配在一个连续地址空间中,则 10-100 这样的需求不可能直接实现,因为子网划分总是固定的,只能间接地通过若干子网和 IP 组合来实现。

但习题上说有 16 位的主机地址空间,但不是只有 8 位吗?