Archive for August, 2009

August 29, 2009
1
2
3
4
5
6
7
#include <stdio.h>
int a[10240] = {1}; //~ 显式初始化a[0]为1的全局数组,编译后,可执行文件的大小为49.0K
int
main()
{
    return 0;
}

  局部对象是在运行时栈上分配的,编译后不占用磁盘空间。未显式初始化或者初始化为0的全局数组,编译器会做相应的记录,以便在程序装入时分配空间。做显式初始化的全局数组,由于初始化的元素个数及元素值不便记录,编译器便在编译时就分配了空间,因此需要占用磁盘空间。

Tags: . 78 views

程序输出:
o.o.o.o.o.o.o.o..o.o.oo.o.o.o.o.o.o.o.o.21
为什么呢?
加上代码中注释掉的互斥锁1、2、3后,输出没有大的变化,只是global变成了20。再注释掉$1、#2,输出结果就正常了。

Tags: . 27 views
August 28, 2009

  管道是Linux支持的 IPC形式之一,具有以下特点:

  • 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;
  • 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);
  • 单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在与内存中。
  • 数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据。
Tags: ,,,. 55 views
August 26, 2009

实现了动态加载标准库中的数学函数库,输入函数名及参数,返回计算结果。

1
2
3
4
5
6
7
8
9
10
11
/*
 * #include <dlfcn.h>
 * void *dlopen( const char *file, int mode );
 * void *dlsym( void *restrict handle, const char *restrict name );
 * char *dlerror();
 * char *dlclose( void *handle );
 * dlopen	使对象文件可被程序访问
 * dlsym	获取执行了 dlopen 函数的对象文件中的符号的地址
 * dlerror	返回上一次出现错误的字符串错误
 * dlclose	关闭目标文件
 */
Tags: ,. 20 views
August 25, 2009
1
void (*signal (int sigNum, void (*sigHandler)(int))) (int);

乍一看这个函数原型就被唬住了,跟个指针似的。仔细分析一下,
*signal (int sigNum, void (*sigHandler)(int))
部分里面
(int sigNum, void (*sigHandler)(int))
优先级高于signal前面的*,所以这是个函数,*只是返回值的一部分,即返回的应该是一个指针。这个指针式什么类型的取决于
(*signal (int sigNum, void (*sigHandler)(int)))
外面的部分,前面是void,后面是(int),可见signal函数返回的是一个函数指针,其函数原型为void f(int)。返回的这个指针与signal的第二个参数的类型是一样的。于是乎,这个bt的函数原型声明还可以这样来定义:

1
2
typedef void sigHandler(int);
sigHandler *signal(int, sigHandler *);

抑或是

1
2
typedef void (*psigHandler)(int);
psigHandler signal(int, psigHandler);

这种声明看起来真累!

Tags: ,. 15 views
0x4000a963 <_dl_runtime_resolve+3>:     movl   0x10(%esp,1),%edx
0x4000a967 <_dl_runtime_resolve+7>:     movl   0xc(%esp,1),%eax
0x4000a96b <_dl_runtime_resolve+11>:    call   0x4000a740 

  指令xchgl %eax,(%esp,1)将printf的地址放入栈顶。最精彩的一条指令当属ret $0×8,它将栈顶元素即printf的地址弹出至程序计数器PC,作为下一条将执行的指令地址,同时,清除堆栈中的0×10和0×8049560。此时堆栈中的情形,就如同直接调用了printf函数,似乎什么都没发生过。

  此外还做了一件重要的工作,就是把前面提到的addr2替换为printf的地址。从而当再次调用printf时jmp *addr1就直接将程序定位到printf,不需要再次加载库libc.so了。

  不知道我说清楚了没有,感觉说的很乱,文字也很乱。:-)

Tags: ,,. 311 views
August 24, 2009

没啥好说的,只是要注意防止m = (r + l) / 2;时m会发生上溢。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template <class T>
int BSearch(T *a, size_t n, T v)
{
    assert(a != NULL && n > 0); //! a == NULL || n <= 0 就坏了:-(
    size_t l = 0,
           r = n -1,
           m = l + (r - l) / 2; //! 勿用m=(l+r)/2;
    while(l <= r)
    {
        if(a[m] == v)
            return (int)m;
        else if(a[m] < v)
            l = m + 1;
        else
            r = m - 1;
    }
    return -1;
}
Tags: ,. 10 views

convert是imagemagick软件包中的一个命令。它可以读取、转换、写入多种格式的图片。图片切割、颜色替换、各种效果的应用,图片的旋转、组合,文本,直线,多边形,椭圆,曲线,附加到图片伸展旋转。这里介绍几个简单的命令,具体的用法请参考man手册或者其官方网站。在Ubuntu中用命令

1
sudo apt-get install imagemagick

来安装,windows下的使用可以到官方网站下载。

Tags: ,,,. 526 views
August 23, 2009

归并排序算法(mergesort)是将一个序列划分为同样大小的两个子序列,然后对两个子序列分别进行排序,最后进行合并操作,将两个子序列合成有序的序列。在合成的过程中,一般的实现都需要开辟一块与原序列大小相同的空间,以进行合并操作。这里介绍一种不需要开辟新的空间就可以进行归并操作的原地归并算法。代码来说事儿:

1
2
3
4
5
6
7
8
9
//~ 原地归并
while(l < r && r < size) //~ 核心算法
{
	while(v[l] <= v[r] && l < r) ++l; //~ 找到左面第一个比v[r]大的v[l]
	size_t to_mv = 0; //~ 计数器
	while(v[r] < v[l] && r < size) ++r, ++to_mv; //~ 右侧找到to_mv个比v[l]小的数
	Exchange(v+l, r-l-to_mv, r-l);//~ 将此to_mv个数移到v[l]前面
	l += to_mv; //~ 改变l,继续下一轮循环
}//~ l >-r 或者 r >= size时归并结束
Tags: ,,. 68 views
生产者-消费者问题:

生产者-消费者问题是经典的同步问题,它描述一组生产者进程(线程)向一组消费者进程(线程)提供消息。它们共享一个有界的缓冲池,生产者向其中投放消息,消费者从中取得消息。生产者-消费者问题是许多具体问题中进程(线程)合作的一个很好的抽象。假定缓冲区中有N个位置,每个位置存放一个消息。当缓冲区未满时,生产者可以投入一个消息,否则该进程(线程)阻塞,直到缓冲区内有空位可放;当缓冲区非空时,消费者可以从中取得一个消息,否则该进程(线程)阻塞,直到缓冲区内有消息可取。

为了模拟这一过程,首先需要设置一个大小为N的缓冲区。修改缓冲区时,需要同步各个进程(线程)以免发生错误(向满的缓冲区投放消息或者从空缓冲区内取出消息)。为此,需要设置两个信号量empty和full用以标识缓冲区中空位数和消息数。另外还需要一个互斥锁mutex以互斥地修改缓冲区。为了便于测试,这里缓冲区的大小设置为5,实际情况下,应该尽量大些,以免生产者和消费者相互等待。

Tags: ,,. 277 views
Page 1 of 41234