2010年10月04日

最近帮别人做了小项目,用MFC,发现在线程中要结束一个模态对话框,直接调用EndDialog会有问题。

通过一个自定义的消息来解决这个问题。

在线程中,给Dialog发送一个自定义的消息,然后在消息中执行EndDialog.

ok,搞定,特此记录一笔。仅此而已。

2009年10月19日

最近打算把skia 移植到trimedia 平台。操作系统为PSOS。先将SKIA移植到WIN32. 目前SKIA移植到WIN32,已经基本完成。去掉了XML的支持。 VIEW里面WIN32的接口,实现还有一点点问题。主要是消息的传递上,还有点问题。 怎么贴图?上传不了???

2005年05月23日

爱上位运算
———————————————————————————–
       2005
41                E-mail: zjneter@163.com
———————————————————————————-


缘起:C语言区别于其它语言的重要特点是支持位运算,使其能够完成汇编语言所能完成的大部分功能。但是学校开设的C语言课程中老师往往将位运算这一章一代而过,好像这一张根本不重要。但是在实际的编程中借助于位运算往往可以设计出简洁的算法,使程序简化,并且获得较高的效率。而且在某些对硬件进行控制的编程中,位运算是必不可少的。因此笔者参考了相关书籍,总结了一些规律和助记口诀,希望对读者有所帮助。

优先级(高—〉低)
 ! ~ 
算术运算符 关系运算符 & ^ | && || 赋值

移位运算  <<   >>
要点 1 它们都是双目运算符,两个运算分量都是整形,结果也是整形。
     2
左移:右边空出的位上补0,左边的位将从字头挤掉,其值相当于乘2
     3
右移:右边的位被挤掉。对于左边移出的空位,如果是正数则空位补0,若为负数,可能补0或补1,这取决于所用的计算机系统。
      
移入0的叫逻辑右移,移入1的叫算术右移,Turbo C采用逻辑右移。

位运算符的应用  (源操作数s 掩码mask)
(1)
按位与—— &
  1
清零特定位 (mask中特定位置0,其它位为1s=s&mask)

  2 取某数中指定位 (mask中特定位置1,其它位为0s=s&mask)

(2) 按位或—— |
   
常用来将源操作数某些位置1,其它位不变。 (mask中特定位置1,其它位为0 s=s|mask)

(3) 位异或—— ^
  1
使特定位的值取反 (mask中特定位置1,其它位为0 s=s^mask)

  2 不引入第三变量,交换两个变量的值  ( a=a1,b=b1)
   
                         操作后状态
    a=a1^b1         a=a^b              a=a1^b1,b=b1
    b=a1^b1^b1      b=a^b              a=a1^b1,b=a1
    a=b1^a1^a1      a=a^b              a=b1,b=a1

位运算应用口诀
 
清零取反要用与,某位置一可用或
 
若要取反和交换,轻轻松松用异或

应用举例
    (1)
判断int型变量a是奇数还是偶数
            |- 0
偶数
 a&1=|
            |- 1
奇数
    (2)
int型变量a的第k (k=0,1,2……sizeof(int))
 a>>k&1
    (3)
int型变量a的第k位清0
 a=a&~(1<<k)
    (4)
int型变量a的第k位置1
 a=a|(1<<k)
    (5) int
型变量循环左移k
 a=a<<k|a>>16-k   (
sizeof(int)=16)
    (6) int
型变量a循环右移k
 a=a>>k|a<<16-k   (
sizeof(int)=16)

例题
 1
实现一个函数itob(),使用移位运算将从键盘上输入的整数转换为它的二进制表示形。
 
解: char * itob(int n,char *ps)
             {
                int i;
                static int size=8*sizeof(int);
                for(i=size-1;i>=0;i–,n>>=1)
                   ps[i]=(1&n)+’0′;
                ps[size]=’\0′;
                return ps;
             }
 2
编写一个函数 invert_end(),反转一个值中最后n位,并将结果返回。
 
解: int  invert_end(int num,int bits)
             {
                int mask=0;
                int bitval=1;
                while(bits– >0)
                {
                   mask|=bitval;
                   bitval<<=1;
                }
                return num^mask;
             }
实战练习
 1
编写一个将二进制字符串转化为数值的函数
  
若有 char *bin="01001001";
         
那么可将bin作为参数传给该函数,使函数返回值为25
 2
编写一个函数,该函数接受一个int参数,并返回该参数中打开的位的数量。
 3
编写一个函数,该函数接受两个参数:一个值和一个位置。如果制定的位上的值是1,函数返回1,否则返回0
总结
  (1)
在了解了各种位运算的操作原理后,最好熟记各运算符的优先级。在阅读别人写的代码是你可以去查书,但自己写程序时还是
     
熟能生巧。
  (2)
如你所见,在不引入第三变量的情况下使用异或运算就可以将两个变量的交换,本文给除了操作过程,你应当仔细分析一下。
     
感觉就像变魔术一般神奇 :)
  (3)
判断一个整数a的奇偶性通常的做法是看 a%2的结果是0还是1,这没什么不对,但是要知道%运算要比相应的位运算慢的多啦,
     
对十个数进行奇偶判断就无所谓啦,哪种方法都ok,但是若要对T数量级的数进行操作,你就不得不考虑一下效率问题了!

  本文主要参考了 C Primer Plus (第四版)》,本文的例题也来自这本书

 转(CSDN)

2005年05月18日

         数组


关于数组的初始化
例:int p[4]={1,2,3,4};
1
未经初始化的数组
  auto
类型的(自动存储类)的数组在初始化之前数组元素是不定的,编译器使用的在存储单元中已有的数值。
 
静态存储式时期的数组自动将所有元素初始化为零
2
部分初始化
  int p[4]={1,2};
 
p[0]=1,p[1]=2,p[3]=p[4]=0;
也就是说如果只初始化了数组中的部分元素,则剩余的元素自动初始化为0,因此如果要将一个数组全部初始化为零可以这样做p[MAX]={0}
3
指定项目初始化 ( C99 )
 
按照传统的方法要对数组的最后一个元素初始化,需要对每个元素都初始化之后才可以对最后一个元素进行初始化。
例如: int a[5]={0,0,0,0,16};
C99标准中可以用其新特性,指定初始化项目来简单的完成上述工作
例如:int a[5]={[5]=16};
在初始化列表中使用带方括号的元素下标可以指定某个特定元素
例: d[8]={1,2,[4]=9,10,11,[1]=15};
d[0]=1,d[1]=15,d[2]=0,d[3]=0,d[4]=9,d[5]=10,d[6]=11
注:指定项目初始化的两个重要特性
 
若在一个指定初始化项目后跟有不止一个值,则这些值将用来对后续的数组元素初始化。因此在d[4]=9之后,d[5].d[6]分别初始化为1011
 
如果多次对一个元素初始化,则最后一次有效.例中d[1]先被初始化为2,在[1]=15之后,d[1]又初始化为15

        指针和数组

c语言中数组和指针总有千丝万缕的联系。表现在以下几个方面
数组名同时也是该数组首元素的地址
 
对于数组f[MAX] f==&f[0]
  &
运算符取得数组元素f[0]的内存地址,因此f&f[0]都是常量且相等
可以使用指针处理数组
 
p[MAX]是一个数组,其首地址为0×00000000那么p+1的值是0×00000001吗?
回答是不一定。因为对一个指针加上1结果是对该指针增加一个存储单元。对于数组地址会增加到下一个元素的首地址,而不一定是一个字节。那么pp+1之间到底相差多少呢?这要有p所指对象的类型来决定。如果数组的类型是type那么pp+1相差 sizeof(type)个字节。
总结: 1 指针的数值就是它所指向的对象的地址,地址的内部表示由硬件决定。
       2
对指针加1等价于对指针的值加上它指向对象的字节大小。
c
语言标准描述数组时,借助了指针的概念,例如a[n]的意思是*(a+n),即先寻址到内存中的a,然后移动n个单位,再取出该内存处的值。
因此 p+2==&p[2], *(p+2)==p[2]
 
在这里要区分 *(p+2)*p+2的不同。由于*运算符的优先级比+要高, *(p+2)得到的是数组p中第三个元素的值。 *P+2得到的是数组p中第一个元素的值与2相加后的结果。

指针数组和指向数组的指针
  int *p[3]
int (*p)[3]有什么区别呢?
1 []
的优先级高于* 因此int *p[3]等价于int *(p[3])括号内显然是一个数组,括号外的部分表明了数组p的类型,因此p是一个含有3个元素的数组,数组的每一个元素是一个指针,而且是指向int型变量的指针。
2 int (*p)[3]
使得指针p指向了一个包含有3个元素的数组,该数组中元素类型为int 可以用下面的方法记忆
     int *p ;
     int a;
     p= &a;
     *p=a;
    
因此(*p)a代替,从字面上看int(*p)[3]替换为int a[3] ,故可以理解p指向了a[3]
指针和多维数组
  int  zippo[4][2];   /*
整数数组的数组*/
 
数组名 zippo是数组首元素的地址 zippo的首元素本身又是包含两个int型变量的数组。
  zippo
得值和&zippo[0]相同,而 zippo[0]的值同其首元素的地址&zippo[0][0]
相同。zippo[0]是一个整数大小的地址,而zippo是两个整数大小对象的地址。
 
对一个指针加1,会对原来的数值加上一个对应类型大小的数值。在这方面zippozippo[0]是不一样的。zippo所指的对象是两个int,zippo[0]所指的对象是一个int
 
对一个指针取值得到的是该指针所指对象的数值
  *(zippo[0])
代表存储在zippo[0][0]中的数值,即一个int
  *zippo
代表其首元素zippo[0]的值,但zippo[0]本身就是一个int数的地址即 &zippo[0][0],所以 *zippo 就是 &zippo[0][0], **zippo <=> *&zippo[0][0] <=> zippo[0][0]

           变长数组

声明变长数组
 C99
标准引入变成数组,它允许使用变量定义数组维数
变长数组有一些限制,变长数组必须是自动存储类的,这意味着他们必须在函数内部或作为函数声明且声明时不可以进行初始化。
 
示例:  int m=2,n=3;
          int a[m][n];
         
这里a是一个二维数组。
 
“变长”的意思是指在程序运行时动态的创建不同维数的数组,而每一次创建以后该数组就是固定大小的,知道其生存期结束。

变长数组作为函数参数
 
由于变长数组维数在运行时确定,故将其作为函数参数可以提高程序的灵活性和适应性。
 
声明一个带变长数组参数的函数
  int sum (int rows, int cols, int ar[rows][cols]);
注: ar的声明中使用了rowscols,所以在参数列表中对rowscols的声明要早于ar
C99
标准规定可以省略函数原型中的名称,但如果省略名称,则需要用星号代替省略的维数。 例如 int sum (int rows, int cols, int ar[*][*]);

 转自:CSDN

太久没更新了. :(

2004年11月26日

GDB调试指南:http://www.lslnet.com/linux/books/gdb_guide.pdf

www.loveunix.net 里面有相当多的资料


以后会继续添加 ^_^

2004年11月25日

 作者:肖文鹏 发文时间:2004.03.22

在为Linux开发应用程序时,绝大多数情况下使用的都是C语言,因此几乎每一位Linux程序员面临的首要问题都是如何灵活运用C编译器。目前 Linux下最常用的C语言编译器是GCC(GNU Compiler Collection),它是GNU项目中符合ANSI C标准的编译系统,能够编译用C、C++和Object C等语言编写的程序。GCC不仅功能非常强大,结构也异常灵活。最值得称道的一点就是它可以通过不同的前端模块来支持各种语言,如Java、 Fortran、Pascal、Modula-3和Ada等。

开放、自由和灵活是Linux的魅力所在,而这一点在GCC上的体现就是程序员通过它能够更好地控制整个编译过程。在使用GCC编译程序时,编译过程可以被细分为四个阶段:

◆ 预处理(Pre-Processing)

◆ 编译(Compiling)

◆ 汇编(Assembling)

◆ 链接(Linking)

Linux程序员可以根据自己的需要让GCC在编译的任何阶段结束,以便检查或使用编译器在该阶段的输出信息,或者对最后生成的二进制文件进行控制,以便通过加入不同数量和种类的调试代码来为今后的调试做好准备。和其它常用的编译器一样,GCC也提供了灵活而强大的代码优化功能,利用它可以生成执行效率更高的代码。

GCC提供了30多条警告信息和三个警告级别,使用它们有助于增强程序的稳定性和可移植性。此外,GCC还对标准的C和C++语言进行了大量的扩展,提高程序的执行效率,有助于编译器进行代码优化,能够减轻编程的工作量。

GCC起步

在学习使用GCC之前,下面的这个例子能够帮助用户迅速理解GCC的工作原理,并将其立即运用到实际的项目开发中去。首先用熟悉的编辑器输入清单1所示的代码:

清单1:hello.c

#include <stdio.h>
int main(void)
{
printf (“Hello world, Linux programming!\n”);
return 0;
}



然后执行下面的命令编译和运行这段程序:

# gcc hello.c -o hello
# ./hello
Hello world, Linux programming!



从程序员的角度看,只需简单地执行一条GCC命令就可以了,但从编译器的角度来看,却需要完成一系列非常繁杂的工作。首先,GCC需要调用预处理程序 cpp,由它负责展开在源文件中定义的宏,并向其中插入“#include”语句所包含的内容;接着,GCC会调用ccl和as将处理后的源代码编译成目标代码;最后,GCC会调用链接程序ld,把生成的目标代码链接成一个可执行程序。

为了更好地理解GCC的工作过程,可以把上述编译过程分成几个步骤单独进行,并观察每步的运行结果。第一步是进行预编译,使用-E参数可以让GCC在预处理结束后停止编译过程:

# gcc -E hello.c -o hello.i



此时若查看hello.cpp文件中的内容,会发现stdio.h的内容确实都插到文件里去了,而其它应当被预处理的宏定义也都做了相应的处理。下一步是将hello.i编译为目标代码,这可以通过使用-c参数来完成:

# gcc -c hello.i -o hello.o



GCC默认将.i文件看成是预处理后的C语言源代码,因此上述命令将自动跳过预处理步骤而开始执行编译过程,也可以使用-x参数让GCC从指定的步骤开始编译。最后一步是将生成的目标文件链接成可执行文件:

# gcc hello.o -o hello



在采用模块化的设计思想进行软件开发时,通常整个程序是由多个源文件组成的,相应地也就形成了多个编译单元,使用GCC能够很好地管理这些编译单元。假设有一个由foo1.c和foo2.c两个源文件组成的程序,为了对它们进行编译,并最终生成可执行程序foo,可以使用下面这条命令:

# gcc foo1.c foo2.c -o foo



如果同时处理的文件不止一个,GCC仍然会按照预处理、编译和链接的过程依次进行。如果深究起来,上面这条命令大致相当于依次执行如下三条命令:

# gcc -c foo1.c -o foo1.o
# gcc -c foo2.c -o foo2.o
# gcc foo1.o foo2.o -o foo



在编译一个包含许多源文件的工程时,若只用一条GCC命令来完成编译是非常浪费时间的。假设项目中有100个源文件需要编译,并且每个源文件中都包含 10000行代码,如果像上面那样仅用一条GCC命令来完成编译工作,那么GCC需要将每个源文件都重新编译一遍,然后再全部连接起来。很显然,这样浪费的时间相当多,尤其是当用户只是修改了其中某一个文件的时候,完全没有必要将每个文件都重新编译一遍,因为很多已经生成的目标文件是不会改变的。要解决这个问题,关键是要灵活运用GCC,同时还要借助像Make这样的工具。

警告提示功能

GCC包含完整的出错检查和警告提示功能,它们可以帮助Linux程序员写出更加专业和优美的代码。先来读读清单2所示的程序,这段代码写得很糟糕,仔细检查一下不难挑出很多毛病:

◆main函数的返回值被声明为void,但实际上应该是int;

◆使用了GNU语法扩展,即使用long long来声明64位整数,不符合ANSI/ISO C语言标准;

◆main函数在终止前没有调用return语句。

清单2:illcode.c

#include <stdio.h>
void main(void)
{
long long int var = 1;
printf(“It is not standard C code!\n”);
}



下面来看看GCC是如何帮助程序员来发现这些错误的。当GCC在编译不符合ANSI/ISO C语言标准的源代码时,如果加上了-pedantic选项,那么使用了扩展语法的地方将产生相应的警告信息:

# gcc -pedantic illcode.c -o illcode
illcode.c: In function `main’:
illcode.c:9: ISO C89 does not support `long long’
illcode.c:8: return type of `main’ is not `int’



需要注意的是,-pedantic编译选项并不能保证被编译程序与ANSI/ISO C标准的完全兼容,它仅仅只能用来帮助Linux程序员离这个目标越来越近。或者换句话说,-pedantic选项能够帮助程序员发现一些不符合 ANSI/ISO C标准的代码,但不是全部,事实上只有ANSI/ISO C语言标准中要求进行编译器诊断的那些情况,才有可能被GCC发现并提出警告。

除了-pedantic之外,GCC还有一些其它编译选项也能够产生有用的警告信息。这些选项大多以-W开头,其中最有价值的当数-Wall了,使用它能够使GCC产生尽可能多的警告信息:

# gcc -Wall illcode.c -o illcode
illcode.c:8: warning: return type of `main’ is not `int’
illcode.c: In function `main’:
illcode.c:9: warning: unused variable `var’



GCC给出的警告信息虽然从严格意义上说不能算作是错误,但却很可能成为错误的栖身之所。一个优秀的Linux程序员应该尽量避免产生警告信息,使自己的代码始终保持简洁、优美和健壮的特性。

在处理警告方面,另一个常用的编译选项是-Werror,它要求GCC将所有的警告当成错误进行处理,这在使用自动编译工具(如Make等)时非常有用。如果编译时带上-Werror选项,那么GCC会在所有产生警告的地方停止编译,迫使程序员对自己的代码进行修改。只有当相应的警告信息消除时,才可能将编译过程继续朝前推进。执行情况如下:

# gcc -Wall -Werror illcode.c -o illcode
cc1: warnings being treated as errors
illcode.c:8: warning: return type of `main’ is not `int’
illcode.c: In function `main’:
illcode.c:9: warning: unused variable `var’



对Linux程序员来讲,GCC给出的警告信息是很有价值的,它们不仅可以帮助程序员写出更加健壮的程序,而且还是跟踪和调试程序的有力工具。建议在用GCC编译源代码时始终带上-Wall选项,并把它逐渐培养成为一种习惯,这对找出常见的隐式编程错误很有帮助。

库依赖

在Linux下开发软件时,完全不使用第三方函数库的情况是比较少见的,通常来讲都需要借助一个或多个函数库的支持才能够完成相应的功能。从程序员的角度看,函数库实际上就是一些头文件(.h)和库文件(.so或者.a)的集合。虽然Linux下的大多数函数都默认将头文件放到/usr/include/ 目录下,而库文件则放到/usr/lib/目录下,但并不是所有的情况都是这样。正因如此,GCC在编译时必须有自己的办法来查找所需要的头文件和库文件。

GCC采用搜索目录的办法来查找所需要的文件,-I选项可以向GCC的头文件搜索路径中添加新的目录。例如,如果在/home/xiaowp/include/目录下有编译时所需要的头文件,为了让GCC能够顺利地找到它们,就可以使用-I选项:

# gcc foo.c -I /home/xiaowp/include -o foo



同样,如果使用了不在标准位置的库文件,那么可以通过-L选项向GCC的库文件搜索路径中添加新的目录。例如,如果在/home/xiaowp/lib/目录下有链接时所需要的库文件libfoo.so,为了让GCC能够顺利地找到它,可以使用下面的命令:

# gcc foo.c -L /home/xiaowp/lib -lfoo -o foo



值得好好解释一下的是-l选项,它指示GCC去连接库文件libfoo.so。Linux下的库文件在命名时有一个约定,那就是应该以lib三个字母开头,由于所有的库文件都遵循了同样的规范,因此在用-l选项指定链接的库文件名时可以省去lib三个字母,也就是说GCC在对-lfoo进行处理时,会自动去链接名为libfoo.so的文件。

Linux下的库文件分为两大类分别是动态链接库(通常以.so结尾)和静态链接库(通常以.a结尾),两者的差别仅在程序执行时所需的代码是在运行时动态加载的,还是在编译时静态加载的。默认情况下,GCC在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库,如果需要的话可以在编译时加上-static选项,强制使用静态链接库。例如,如果在/home/xiaowp/lib/目录下有链接时所需要的库文件libfoo.so和 libfoo.a,为了让GCC在链接时只用到静态链接库,可以使用下面的命令:

# gcc foo.c -L /home/xiaowp/lib -static -lfoo -o foo

 作者:肖文鹏 发文时间:2004.03.22


代码优化

代码优化指的是编译器通过分析源代码,找出其中尚未达到最优的部分,然后对其重新进行组合,目的是改善程序的执行性能。GCC提供的代码优化功能非常强大,它通过编译选项-On来控制优化代码的生成,其中n是一个代表优化级别的整数。对于不同版本的GCC来讲,n的取值范围及其对应的优化效果可能并不完全相同,比较典型的范围是从0变化到2或3。

编译时使用选项-O可以告诉GCC同时减小代码的长度和执行时间,其效果等价于-O1。在这一级别上能够进行的优化类型虽然取决于目标处理器,但一般都会包括线程跳转(Thread Jump)和延迟退栈(Deferred Stack Pops)两种优化。选项-O2告诉GCC除了完成所有-O1级别的优化之外,同时还要进行一些额外的调整工作,如处理器指令调度等。选项-O3则除了完成所有-O2级别的优化之外,还包括循环展开和其它一些与处理器特性相关的优化工作。通常来说,数字越大优化的等级越高,同时也就意味着程序的运行速度越快。许多Linux程序员都喜欢使用-O2选项,因为它在优化长度、编译时间和代码大小之间,取得了一个比较理想的平衡点。

下面通过具体实例来感受一下GCC的代码优化功能,所用程序如清单3所示。

清单3:optimize.c

#include <stdio.h>
int main(void)
{
double counter;
double result;
double temp;
for (counter = 0;
counter < 2000.0 * 2000.0 * 2000.0 / 20.0 + 2020;
counter += (5 – 1) / 4) {
temp = counter / 1979;
result = counter;
}
printf(“Result is %lf\n”, result);
return 0;
}



首先不加任何优化选项进行编译:

# gcc -Wall optimize.c -o optimize



借助Linux提供的time命令,可以大致统计出该程序在运行时所需要的时间:

# time ./optimize
Result is 400002019.000000
real 0m14.942s
user 0m14.940s
sys 0m0.000s



接下去使用优化选项来对代码进行优化处理:

# gcc -Wall -O optimize.c -o optimize



在同样的条件下再次测试一下运行时间:

# time ./optimize
Result is 400002019.000000
real 0m3.256s
user 0m3.240s
sys 0m0.000s



对比两次执行的输出结果不难看出,程序的性能的确得到了很大幅度的改善,由原来的14秒缩短到了3秒。这个例子是专门针对GCC的优化功能而设计的,因此优化前后程序的执行速度发生了很大的改变。尽管GCC的代码优化功能非常强大,但作为一名优秀的Linux程序员,首先还是要力求能够手工编写出高质量的代码。如果编写的代码简短,并且逻辑性强,编译器就不会做更多的工作,甚至根本用不着优化。

优化虽然能够给程序带来更好的执行性能,但在如下一些场合中应该避免优化代码:

◆ 程序开发的时候 优化等级越高,消耗在编译上的时间就越长,因此在开发的时候最好不要使用优化选项,只有到软件发行或开发结束的时候,才考虑对最终生成的代码进行优化。

◆ 资源受限的时候 一些优化选项会增加可执行代码的体积,如果程序在运行时能够申请到的内存资源非常紧张(如一些实时嵌入式设备),那就不要对代码进行优化,因为由这带来的负面影响可能会产生非常严重的后果。

◆ 跟踪调试的时候 在对代码进行优化的时候,某些代码可能会被删除或改写,或者为了取得更佳的性能而进行重组,从而使跟踪和调试变得异常困难。

调试

一个功能强大的调试器不仅为程序员提供了跟踪程序执行的手段,而且还可以帮助程序员找到解决问题的方法。对于Linux程序员来讲,GDB(GNU Debugger)通过与GCC的配合使用,为基于Linux的软件开发提供了一个完善的调试环境。

默认情况下,GCC在编译时不会将调试符号插入到生成的二进制代码中,因为这样会增加可执行文件的大小。如果需要在编译时生成调试符号信息,可以使用 GCC的-g或者-ggdb选项。GCC在产生调试符号时,同样采用了分级的思路,开发人员可以通过在-g选项后附加数字1、2或3来指定在代码中加入调试信息的多少。默认的级别是2(-g2),此时产生的调试信息包括扩展的符号表、行号、局部或外部变量信息。级别3(-g3)包含级别2中的所有调试信息,以及源代码中定义的宏。级别1(-g1)不包含局部变量和与行号有关的调试信息,因此只能够用于回溯跟踪和堆栈转储之用。回溯跟踪指的是监视程序在运行过程中的函数调用历史,堆栈转储则是一种以原始的十六进制格式保存程序执行环境的方法,两者都是经常用到的调试手段。

GCC产生的调试符号具有普遍的适应性,可以被许多调试器加以利用,但如果使用的是GDB,那么还可以通过-ggdb选项在生成的二进制代码中包含GDB 专用的调试信息。这种做法的优点是可以方便GDB的调试工作,但缺点是可能导致其它调试器(如DBX)无法进行正常的调试。选项-ggdb能够接受的调试级别和-g是完全一样的,它们对输出的调试符号有着相同的影响。

需要注意的是,使用任何一个调试选项都会使最终生成的二进制文件的大小急剧增加,同时增加程序在执行时的开销,因此调试选项通常仅在软件的开发和调试阶段使用。调试选项对生成代码大小的影响从下面的对比过程中可以看出来:

# gcc optimize.c -o optimize
# ls optimize -l
-rwxrwxr-x 1 xiaowp xiaowp 11649 Nov 20 08:53 optimize (未加调试选项)
# gcc -g optimize.c -o optimize
# ls optimize -l
-rwxrwxr-x 1 xiaowp xiaowp 15889 Nov 20 08:54 optimize (加入调试选项)



虽然调试选项会增加文件的大小,但事实上Linux中的许多软件在测试版本甚至最终发行版本中仍然使用了调试选项来进行编译,这样做的目的是鼓励用户在发现问题时自己动手解决,是Linux的一个显著特色。

下面还是通过一个具体的实例说明如何利用调试符号来分析错误,所用程序见清单4所示。

清单4:crash.c

#include <stdio.h>
int main(void)
{
int input =0;
printf(“Input an integer:”);
scanf(“%d”, input);
printf(“The integer you input is %d\n”, input);
return 0;
}



编译并运行上述代码,会产生一个严重的段错误(Segmentation fault)如下:

# gcc -g crash.c -o crash
# ./crash
Input an integer:10
Segmentation fault



为了更快速地发现错误所在,可以使用GDB进行跟踪调试,方法如下:

# gdb crash
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
……
(gdb)



当GDB提示符出现的时候,表明GDB已经做好准备进行调试了,现在可以通过run命令让程序开始在GDB的监控下运行:

(gdb) run
Starting program: /home/xiaowp/thesis/gcc/code/crash
Input an integer:10

Program received signal SIGSEGV, Segmentation fault.
0×4008576b in _IO_vfscanf_internal () from /lib/libc.so.6



仔细分析一下GDB给出的输出结果不难看出,程序是由于段错误而导致异常中止的,说明内存操作出了问题,具体发生问题的地方是在调用 _IO_vfscanf_internal ( )的时候。为了得到更加有价值的信息,可以使用GDB提供的回溯跟踪命令backtrace,执行结果如下:

(gdb) backtrace
#0 0×4008576b in _IO_vfscanf_internal () from /lib/libc.so.6
#1 0xbffff0c0 in ?? ()
#2 0×4008e0ba in scanf () from /lib/libc.so.6
#3 0×08048393 in main () at crash.c:11
#4 0×40042917 in __libc_start_main () from /lib/libc.so.6



跳过输出结果中的前面三行,从输出结果的第四行中不难看出,GDB已经将错误定位到crash.c中的第11行了。现在仔细检查一下:

(gdb) frame 3
#3 0×08048393 in main () at crash.c:11
11 scanf(“%d”, input);



使用GDB提供的frame命令可以定位到发生错误的代码段,该命令后面跟着的数值可以在backtrace命令输出结果中的行首找到。现在已经发现错误所在了,应该将

scanf(“%d”, input);
改为
scanf(“%d”, &input);



完成后就可以退出GDB了,命令如下:

(gdb) quit



GDB的功能远远不止如此,它还可以单步跟踪程序、检查内存变量和设置断点等。

调试时可能会需要用到编译器产生的中间结果,这时可以使用-save-temps选项,让GCC将预处理代码、汇编代码和目标代码都作为文件保存起来。如果想检查生成的代码是否能够通过手工调整的办法来提高执行性能,在编译过程中生成的中间文件将会很有帮助,具体情况如下:

# gcc -save-temps foo.c -o foo
# ls foo*
foo foo.c foo.i foo.s



GCC支持的其它调试选项还包括-p和-pg,它们会将剖析(Profiling)信息加入到最终生成的二进制代码中。剖析信息对于找出程序的性能瓶颈很有帮助,是协助Linux程序员开发出高性能程序的有力工具。在编译时加入-p选项会在生成的代码中加入通用剖析工具(Prof)能够识别的统计信息,而 -pg选项则生成只有GNU剖析工具(Gprof)才能识别的统计信息。

最后提醒一点,虽然GCC允许在优化的同时加入调试符号信息,但优化后的代码对于调试本身而言将是一个很大的挑战。代码在经过优化之后,在源程序中声明和使用的变量很可能不再使用,控制流也可能会突然跳转到意外的地方,循环语句有可能因为循环展开而变得到处都有,所有这些对调试来讲都将是一场噩梦。建议在调试的时候最好不使用任何优化选项,只有当程序在最终发行的时候才考虑对其进行优化。

2004年11月17日

想看更多的流媒体资源或其他的资源:可以看看:http://www.umsky.com/knowledge/Streaming/

voip书籍:
http://www.chinagk.org/technology/IPTech/001.htm
全球VOIP联盟
http://www.microvoip.com/thdmain01.htm


RTP库:
http://research.edm.luc.ac.be/jori/jrtplib/jrtplib.html



DVB资源网站:
http://www.dvbcn.com



老古开发网:(里面有很多关于单片机和嵌入式等等,各个方面的资料).
http://www.laogu.com/download.aspx?page=28


智能未来:(有些音视频的编码资料下载)
http://www.try2it.com/fir.asp?o=5


陆其明的站点:(流媒体开发)
http://hqtech.nease.net/Document.htm


DirectShow Developer Q & A
http://www.gdcl.co.uk/q_and_a.htm



G729A的免费库:
http://www.voiceage.com/codecsite/openinit_g729eula.php


其他一些源代码的:
http://cvs.winehq.com/cvsweb/wine/dlls


Dialogic OKI <-> G.726 transcoders
http://freespace.virgin.net/joe.carter/codecs/


微软BLOG集:
http://blogs.msdn.com/


一些电子书集下载:
http://leon83.com/leon/download/index.jsp?ct=book%2FNetwork&image=false


H.245协议的VC++实现
http://www.sic.org.cn/lunwen/004.htm


饮水思源 — 精华区文章阅读
http://bbs.sjtu.edu.cn/bbsanc?path=/groups/GROUP_3/C/.index


在线翻译的网站:
http://www.worldlingo.com/wl/translate


RFC文档目录
http://www.leepig.com/rfc/


C++, Java, C#, OO, GP的网站
http://www.allaboutprogram.com/


开源的即时通信协议jabber项目:
http://www.jabber.org/software/libraries.php


 


用于MPEG-4视听流的RTP负载格式
http://www.umsky.com/knowledge/Streaming/RFC3016-cn


MPEG4IP: Open Source, Open Standards, Open Streaming
http://mpeg4ip.sourceforge.net/


主要研究:Internet real-time and multimedia services and protocols, ubiquitous computing, mobile systems, quality of service, modeling and analysis of computer-communication networks, operating systems, network security.

http://www.cs.columbia.edu/~hgs/



SIP and RTP Stack 相关:



基于SIP STACK 的开源项目:
http://www.vovida.org/


H323的开源:
www.openh323.org


在Vovida的基础上实现自己的SIP协议栈
http://www.ctiforum.com/technology/Voip/2003/08/voip0802.htm


vchelp上的:基于SIP的软终端项目预研
http://www.copathway.com/copathway/project_view.asp?prj_id=265



jrtplib: C++; License: Free; Homepage: http://lumumba.luc.ac.be/jori/jrtplib/jrtplib.html


Common Multimedia Library: from UCL London, includes RTP stack; C; License: Free; Homepage: http://www-mice.cs.ucl.ac.uk/multimedia/software/common/


ortp: C; License: LGPL; Homepage: http://www.linphone.org/ortp/; without RTCP, from linphone


GNU ccRTP: C++; License: GPL (with linking exception); Homepage: http://www.gnu.org/software/ccrtp/


LIVE.COM Streaming Media: C++; License: LGPL; Homepage: http://live.com/liveMedia/


Morgan RTP DirectShow Filters: C++; License: ?; Homepage: http://www.morgan-multimedia.com/RTP/; based on liveMedia library


RTP from vovida.org: C++; License: Free; Homepage: http://www.vovida.org/protocols/downloads/rtp/


RTPlib: RTP library from Lucent Technologies/Cloumbia University; C; License: Non-exklusive source code license; Homepage: http://www-out.bell-labs.com/project/RTPlib/


librtp: C; License: GPL; Homepage: http://gphone.sourceforge.net/template.php3?page=librtp; from Gnome-o-phone



SIP Stacksdissipate:  Homepage: http://www.div8.net/dissipate/; The original dissipate by Billy Biggs.


dissipate2: GPL; Homepage: http://www.wirlab.net/kphone/; A enhanced dissipate, is part of the kphone distribution.


GNU osip;LGPL; Homepage: http://www.gnu.org/software/osip/; Also known as libosip. Note: The interface of osip has been changed and from now on it will be called osip2!


GNU eXosip;  Homepage: http://savannah.nongnu.org/projects/exosip/; The extensible osip: “…It aims to implement a simple high layer API to control the SIP for sessions establishements and common extensions. Once completed, this eXtended library should provide an API for call management, messaging and presence features….


SIP from vovida.org: C++; License: Vovida Software License; Homepage: http://www.vovida.org/protocols/downloads/sip/



RTP ApplicationsRAT – Robust Audio Tool; Homepage: http://www-mice.cs.ucl.ac.uk/multimedia/software/rat/


JMF – Java Media Framework: Can receive and send RTP streams; Homepage: http://java.sun.com/products/java-media/jmf/


MP3/RTP Plugin for Winamp: Homepage: http://www.live.com/multikit/winamp-plugin.html


Vomit – Voice over Missconfigured Internet Telephones:  Homepage: http://vomit.xtdnet.nl


RTP Tools: Several RTP utilities from the Columbia University; Homepage: http://www.cs.columbia.edu/IRT/software/rtptools/


UDP Packet Reflector/Forwarder: A tiny tool which forwards or reflects UDP packets. You can also add delay and packet loss. Very useful if you want to test RTP applications. Homepage: http://www.cs.ucl.ac.uk/staff/s.bhatti/teaching/z02/reflector.html.


 


SIP Phone (User Agent, Softphone, Proxy)


Ubiquity User Agent: Java based SIP Client for Windows, very useful, you have to register (free) to get an license; Homepage: http://www.ubiquity.net/useragent.php


Linphone: A SIP Softphone for Linux (GNOME), needs libosip ans oRTP; Homepage: http://www.linphone.org/


KPhone: A SIP Softphone for Linux (KDE); Homepage: http://www.wirlab.net/kphone/index.html


Vovida: Complete SIP Suite for Linux (Uaser Agent, Proxy, …), very, very big software contruct; Homepage: Vovida.org


Siphon: Linux SIP Softphone; Homepage: http://siphon.sourceforge.net/index.html


AVAZ SIP Phone: Cool looking SIP Phone for Windows, crashes very often at my PC, but works well on my friends PC; Homepage:http://www.avaz.com/products/software/sip/index.html


EZ-Phone (Evaluation Version): SIP Phone for Windows; Homepage: http://www.hssworld.com/voip/download.htm


MySIP: SIP User Agent from Siemens; Homepage: http://www.mysip.ch/



SJPhone: SIP and H.323 Softphone for Windows, Linux and PocketPC from: http://www.sjlabs.com/. The configuration for SIP is a little bit tweaky. And there must not be another SIP client running on port 5060 or the SJPhone won’t work.


instant xpressa: The software version of the xpressa SIP phone from pingtel: http://www.pingtel.com/appdev.jsp; A really impressive SIP phone with a lot of features. Can be extended with Java programs, but no free version available.


xphone: A SIP client for Windows and Windows CE, http://xphone.xten.net/. The beta version is free.


SIPPS: SIP softphone with answering machine and a lot of features, but, IMHO, a not very intuitive user interface, which should be better in the next version (try it yourself).http://www.sippstar.com/. A Demo for testing is available.


 



 

2004年11月15日


//使用priority_queue:可以时vector中保存的数,做顺序/倒序的排列(利用自定义的比较函数 )
//对于那些在使用非常注重顺序的地方,可以说简单,方便,效率高。
//在实时音频流的接收端,利用priority_queue,做抖动处理
//将非常简单。可以采用类似的下面的处理方法,对收到seq number
//做排序处理



#include <iostream>
#include <queue>
using  namespace std;


typedef struct _tagTest
{
 int seq;
 bool operator <  (_tagTest &a) //重载运算符号
 {
  if(seq < a.seq)
   return true;
  return false;
 }


 bool operator >= (_tagTest &a) ////重载运算符号
 {
  return !(*this<a);
 }
}test;



typedef struct _tagcompare //自定义比较的函数
{
 bool operator() (test *a, test *b)
 {
  return *a >= *b;
 }
}compare;


typedef std::priority_queue<test *, std::vector<test * >, compare > TEST_QUEUE;


int main(int argc, char* argv[])
{
 printf(“Hello World!\n”);


 TEST_QUEUE test_queue;
    test* t= new test;
 t->seq = 1;
 test_queue.push(t);
 cout<<t->seq<<” “;


 


 test* t1= new test;
 t1->seq = 30;
 test_queue.push(t1);
 cout<<t1->seq<<” “;


 test* t2= new test;
 t2->seq = 5;
 test_queue.push(t2);
 cout<<t2->seq<<” “;


 test* t3= new test;
 t3->seq = 3;
 test_queue.push(t3);
 cout<<t3->seq<<” “;


   cout<<endl;
 for(int i=0; i = test_queue.size();i++)
 {
  test* pt = test_queue.top();
  test_queue.pop();
  cout<< pt->seq<<” “; //结果为:1,3,5,30
  delete pt;
  pt = NULL;
  
 }


 char c;
 cout<<endl<<”please entry any key…”<<endl;
 cin>>c;


 


 return 0;
}
2004年11月15日