http://www.lifewithqmail.org/LWQ-CN.html#preparation
http://www.google.cn/search?hl=zh-CN&newwindow=1&client=firefox-a&rls=org.mozilla%3Azh-CN%3Aofficial&q=%E9%82%AE%E4%BB%B6%E4%BC%A0%E8%BE%93%E6%B5%81%E7%A8%8B+blog&btnG=Google+%E6%90%9C%E7%B4%A2&meta=&aq=f&oq=
http://www.google.cn/search?hl=zh-CN&newwindow=1&client=firefox-a&rls=org.mozilla%3Azh-CN%3Aofficial&q=%E9%82%AE%E4%BB%B6%E4%BC%A0%E8%BE%93%E6%B5%81%E7%A8%8B+blog&btnG=Google+%E6%90%9C%E7%B4%A2&meta=&aq=f&oq=
08年初十四夜游西湖断桥有感:
月明灯稀 波澜不惊 吾独徙断桥之上 环举宇内 街灯渐次 映带左右 昔流觞曲水 沙石黯然 俱人蛇相恋 千古佳作 包举宇内 囊括四海之爱心人神共知 然时隔境迁 情形兀然 水锁白练 金山水淹 法海造孽 人神共愤 现山色俱粉 月点波心 好一个月圆风轻锁姻缘 情深似海送饯行 有心飞扬醉原形 无心点水红拆尘 道一个姻缘总是前世定 算来不差半毫分 人生姻缘如梦 好自珍重 潜龙勿用 人间作弄.
东阳于西湖三公园
2008-2-20
注:潜龙勿用:在潜伏时期还不能发挥作用,须坚定信念,隐忍待机,不可轻举妄动!
月明灯稀 波澜不惊 吾独徙断桥之上 环举宇内 街灯渐次 映带左右 昔流觞曲水 沙石黯然 俱人蛇相恋 千古佳作 包举宇内 囊括四海之爱心人神共知 然时隔境迁 情形兀然 水锁白练 金山水淹 法海造孽 人神共愤 现山色俱粉 月点波心 好一个月圆风轻锁姻缘 情深似海送饯行 有心飞扬醉原形 无心点水红拆尘 道一个姻缘总是前世定 算来不差半毫分 人生姻缘如梦 好自珍重 潜龙勿用 人间作弄.
东阳于西湖三公园
2008-2-20
注:潜龙勿用:在潜伏时期还不能发挥作用,须坚定信念,隐忍待机,不可轻举妄动!
"VIM工作在与VI不兼容模式下
"set nocompatible
set nocp
"不备份文件
set nobackup
" use mouse everywhere
set mouse=a (再用secure时后要是选择了拖动自动复制,最好不要改选项)
" wrap lines
set wrap
"显示行号
"set nu
"设置匹配模式,类似当输入一个左括号时会匹配相应的那个右括号
set showmatch
"去除vim的GUI版本中的toolbar
set guioptions-=T
"VIM的状态栏标尺
"set ruler
set ru
"检测文件的类型
filetype on
"记录历史的行数
set history=1000
"背景使用黑色
set background=dark
"查找时高亮显示关键字
set hls
"查找时自动找到第一个单词
set incsearch
#设置配色方案
colorscheme murphy
"设置TAB的宽度为4个空格
"set ts=4
set tabstop=4
"行间交错的宽度为4个空格
set shiftwidth=4
"语法高亮度显示
syntax on
"使用自动对齐
"set autoindent
set ai
"智能的选择对齐方式
"set smartindent
set si
"which tags files CTRL-] will search
set tags=./tags,./../tags,./../../tags,./**/tags
"支持C/C++的缩进
set cin
"方便使用taglist
nmap <F8> : Tlist <CR>
"方便使用A.vim插件
nmap <F7> :A<CR>
"方便执行python程序
map <F12> :!python.exe %<CR>
"把tab展开为空格
set expandtab
if(has("gui_running"))
" 图形界面下的设置
else
" 字符界面下的设置
endif
"set nocompatible
set nocp
"不备份文件
set nobackup
" use mouse everywhere
set mouse=a (再用secure时后要是选择了拖动自动复制,最好不要改选项)
" wrap lines
set wrap
"显示行号
"set nu
"设置匹配模式,类似当输入一个左括号时会匹配相应的那个右括号
set showmatch
"去除vim的GUI版本中的toolbar
set guioptions-=T
"VIM的状态栏标尺
"set ruler
set ru
"检测文件的类型
filetype on
"记录历史的行数
set history=1000
"背景使用黑色
set background=dark
"查找时高亮显示关键字
set hls
"查找时自动找到第一个单词
set incsearch
#设置配色方案
colorscheme murphy
"设置TAB的宽度为4个空格
"set ts=4
set tabstop=4
"行间交错的宽度为4个空格
set shiftwidth=4
"语法高亮度显示
syntax on
"使用自动对齐
"set autoindent
set ai
"智能的选择对齐方式
"set smartindent
set si
"which tags files CTRL-] will search
set tags=./tags,./../tags,./../../tags,./**/tags
"支持C/C++的缩进
set cin
"方便使用taglist
nmap <F8> : Tlist <CR>
"方便使用A.vim插件
nmap <F7> :A<CR>
"方便执行python程序
map <F12> :!python.exe %<CR>
"把tab展开为空格
set expandtab
if(has("gui_running"))
" 图形界面下的设置
else
" 字符界面下的设置
endif
#include <stdlib.h>
#include "ldap.h"
#include "stdio.h"
int main()
{
LDAP *ld;
LDAPMessage *res,*e;
int i,version;
char *server;
int port;
char *dn;
char *a;
BerElement *ptr;
char **vals;
char **ppValue = NULL;
char *sdn;
server="10.210.72.141";
port = 389;
//联接服务器
printf("hello the world");
if( (ld = ldap_open(server, port )) == NULL )
{
printf("NO CONNECT");
exit( 1 );
}else{
printf("ldap_open successful\n");
}
version = LDAP_VERSION2;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
if(ldap_simple_bind_s(ld,"cn=Directory Manager","1234qwer")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s by xiangdong2" );
exit( 1 );
}else{
printf("Ldap_bind succesful\n");
}
sdn="dc=sina,dc=net";
if (ldap_search_s(ld,sdn,LDAP_SCOPE_SUBTREE,"(entDefaultDomain=testquanjun1.sina.net)",NULL,0,&res)
!= LDAP_SUCCESS)
{
ldap_perror(ld,"ldap_search_s");
exit(1);
}else{
printf("ldap_search_s is successful\n");
}
for(e=ldap_first_entry(ld,res);e!=NULL;e=ldap_next_entry(ld,res))
{
//取出DN
dn=ldap_get_dn(ld,e);
printf("dn: %s \n",dn);
ldap_memfree( dn );
//对条目的属性进行逐条分析
for ( a = ldap_first_attribute( ld, e, &ptr );a != NULL;a = ldap_next_attribute( ld, e, ptr ) )
{
printf( "%s:",a );
vals = ldap_get_values( ld, e, a );
for ( i = 0; vals[i] != NULL; i++ )
{
printf("%s",vals[i]);
}
printf("\n");
ldap_value_free( vals );
}
printf("\n");
}
ldap_msgfree(res);
ldap_unbind(ld);
}
#include "ldap.h"
#include "stdio.h"
int main()
{
LDAP *ld;
LDAPMessage *res,*e;
int i,version;
char *server;
int port;
char *dn;
char *a;
BerElement *ptr;
char **vals;
char **ppValue = NULL;
char *sdn;
server="10.210.72.141";
port = 389;
//联接服务器
printf("hello the world");
if( (ld = ldap_open(server, port )) == NULL )
{
printf("NO CONNECT");
exit( 1 );
}else{
printf("ldap_open successful\n");
}
version = LDAP_VERSION2;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
if(ldap_simple_bind_s(ld,"cn=Directory Manager","1234qwer")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s by xiangdong2" );
exit( 1 );
}else{
printf("Ldap_bind succesful\n");
}
sdn="dc=sina,dc=net";
if (ldap_search_s(ld,sdn,LDAP_SCOPE_SUBTREE,"(entDefaultDomain=testquanjun1.sina.net)",NULL,0,&res)
!= LDAP_SUCCESS)
{
ldap_perror(ld,"ldap_search_s");
exit(1);
}else{
printf("ldap_search_s is successful\n");
}
for(e=ldap_first_entry(ld,res);e!=NULL;e=ldap_next_entry(ld,res))
{
//取出DN
dn=ldap_get_dn(ld,e);
printf("dn: %s \n",dn);
ldap_memfree( dn );
//对条目的属性进行逐条分析
for ( a = ldap_first_attribute( ld, e, &ptr );a != NULL;a = ldap_next_attribute( ld, e, ptr ) )
{
printf( "%s:",a );
vals = ldap_get_values( ld, e, a );
for ( i = 0; vals[i] != NULL; i++ )
{
printf("%s",vals[i]);
}
printf("\n");
ldap_value_free( vals );
}
printf("\n");
}
ldap_msgfree(res);
ldap_unbind(ld);
}
0 LDAP_SUCCESS Success
1 LDAP_OPERATIONS_ERROR Operations error
2 LDAP_PROTOCOL_ERROR Protocol error
3 LDAP_TIMELIMIT_EXCEEDED Timelimit exceeded
4 LDAP_SIZELIMIT_EXCEEDED Sizelimit exceeded
5 LDAP_COMPARE_FALSE Compare false
6 LDAP_COMPARE_TRUE Compare true
7 LDAP_STRONG_AUTH_NOT_SUPPORTED Strong authentication not supported
8 LDAP_STRONG_AUTH_REQUIRED Strong authentication required
9 LDAP_PARTIAL_RESULTS Partial results
16 LDAP_NO_SUCH_ATTRIBUTE No such attribute
17 LDAP_UNDEFINED_TYPE Undefined attribute type
18 LDAP_INAPPROPRIATE_MATCHING Inappropriate matching
19 LDAP_CONSTRAINT_VIOLATION Constraint violation
20 LDAP_TYPE_OR_VALUE_EXISTS Type or value exists
21 LDAP_INVALID_SYNTAX Invalid syntax
32 LDAP_NO_SUCH_OBJECT No such object
33 LDAP_ALIAS_PROBLEM Alias problem
34 LDAP_INVALID_DN_SYNTAX Invalid DN syntax
35 LDAP_IS_LEAF Object is a leaf
36 LDAP_ALIAS_DEREF_PROBLEM Alias dereferencing problem
48 LDAP_INAPPROPRIATE_AUTH Inappropriate authentication
49 LDAP_INVALID_CREDENTIALS Invalid credentials
50 LDAP_INSUFFICIENT_ACCESS Insufficient access
51 LDAP_BUSY DSA is busy
52 LDAP_UNAVAILABLE DSA is unavailable
53 LDAP_UNWILLING_TO_PERFORM DSA is unwilling to perform
54 LDAP_LOOP_DETECT Loop detected
64 LDAP_NAMING_VIOLATION Naming violation
65 LDAP_OBJECT_CLASS_VIOLATION Object class violation
66 LDAP_NOT_ALLOWED_ON_NONLEAF Operation not allowed on nonleaf
67 LDAP_NOT_ALLOWED_ON_RDN Operation not allowed on RDN
68 LDAP_ALREADY_EXISTS Already exists
69 LDAP_NO_OBJECT_CLASS_MODS Cannot modify object class
70 LDAP_RESULTS_TOO_LARGE Results too large
80 LDAP_OTHER Unknown error
81 LDAP_SERVER_DOWN Can't contact LDAP server
82 LDAP_LOCAL_ERROR Local error
83 LDAP_ENCODING_ERROR Encoding error
84 LDAP_DECODING_ERROR Decoding error
85 LDAP_TIMEOUT Timed out
86 LDAP_AUTH_UNKNOWN Unknown authentication method
87 LDAP_FILTER_ERROR Bad search filter
88 LDAP_USER_CANCELLED User cancelled operation
89 LDAP_PARAM_ERROR Bad parameter to an ldap routine
90 LDAP_NO_MEMORY Out of memory
1 LDAP_OPERATIONS_ERROR Operations error
2 LDAP_PROTOCOL_ERROR Protocol error
3 LDAP_TIMELIMIT_EXCEEDED Timelimit exceeded
4 LDAP_SIZELIMIT_EXCEEDED Sizelimit exceeded
5 LDAP_COMPARE_FALSE Compare false
6 LDAP_COMPARE_TRUE Compare true
7 LDAP_STRONG_AUTH_NOT_SUPPORTED Strong authentication not supported
8 LDAP_STRONG_AUTH_REQUIRED Strong authentication required
9 LDAP_PARTIAL_RESULTS Partial results
16 LDAP_NO_SUCH_ATTRIBUTE No such attribute
17 LDAP_UNDEFINED_TYPE Undefined attribute type
18 LDAP_INAPPROPRIATE_MATCHING Inappropriate matching
19 LDAP_CONSTRAINT_VIOLATION Constraint violation
20 LDAP_TYPE_OR_VALUE_EXISTS Type or value exists
21 LDAP_INVALID_SYNTAX Invalid syntax
32 LDAP_NO_SUCH_OBJECT No such object
33 LDAP_ALIAS_PROBLEM Alias problem
34 LDAP_INVALID_DN_SYNTAX Invalid DN syntax
35 LDAP_IS_LEAF Object is a leaf
36 LDAP_ALIAS_DEREF_PROBLEM Alias dereferencing problem
48 LDAP_INAPPROPRIATE_AUTH Inappropriate authentication
49 LDAP_INVALID_CREDENTIALS Invalid credentials
50 LDAP_INSUFFICIENT_ACCESS Insufficient access
51 LDAP_BUSY DSA is busy
52 LDAP_UNAVAILABLE DSA is unavailable
53 LDAP_UNWILLING_TO_PERFORM DSA is unwilling to perform
54 LDAP_LOOP_DETECT Loop detected
64 LDAP_NAMING_VIOLATION Naming violation
65 LDAP_OBJECT_CLASS_VIOLATION Object class violation
66 LDAP_NOT_ALLOWED_ON_NONLEAF Operation not allowed on nonleaf
67 LDAP_NOT_ALLOWED_ON_RDN Operation not allowed on RDN
68 LDAP_ALREADY_EXISTS Already exists
69 LDAP_NO_OBJECT_CLASS_MODS Cannot modify object class
70 LDAP_RESULTS_TOO_LARGE Results too large
80 LDAP_OTHER Unknown error
81 LDAP_SERVER_DOWN Can't contact LDAP server
82 LDAP_LOCAL_ERROR Local error
83 LDAP_ENCODING_ERROR Encoding error
84 LDAP_DECODING_ERROR Decoding error
85 LDAP_TIMEOUT Timed out
86 LDAP_AUTH_UNKNOWN Unknown authentication method
87 LDAP_FILTER_ERROR Bad search filter
88 LDAP_USER_CANCELLED User cancelled operation
89 LDAP_PARAM_ERROR Bad parameter to an ldap routine
90 LDAP_NO_MEMORY Out of memory
面向对象编程(OOP)是我们编程的一项基本技能,PHP4对OOP提供了良好的支持。如何使用OOP的思想来进行PHP的高级编程,对于提高PHP编程能力和规划好Web开发构架都是非常有意义的。下面我们就通过实例来说明使用PHP的OOP进行编程的实际意义和应用方法。
我们通常在做一个有数据库后台的网站的时候,都会考虑到程序需要适用于不同的应用环境。和其他编程语言有所不同的是,在PHP中,操作数据库的是一系列的具体功能函数(如果你不使用ODBC接口的话)。这样做虽然效率很高,但是封装却不够。如果有一个统一的数据库接口,那么我们就可以不对程序做任何修改而适用于多种数据库,从而使程序的移植性和跨平台能力都大大提高。
在PHP中要完成OOP,需要进行对象封装,也就是编写类。我们可以通过生成一个新的SQL类实现对数据库的简单封装。例如:
< ?
class SQL
{
var $Driver; //实际操作的数据库驱动子类
var $connection; //共用的数据库连接变量
function DriverRegister($d)
{
if($d!="")
{
$include_path = ini_get("include_path");
$DriverFile = $include_path."/".$d.".php";
//驱动的存放路径必须在PHP.ini文件中设定的INCLUDE_PATH下
if( file_exists( $DriverFile)) //查找驱动是否存在
{
include($DriverFile);
$this->Driver = new $d();
// 根据驱动名称生成相应的数据库驱动类
return true;
}
}
return false; //注册驱动失败
}
function Connect($host,$user,$passwd,$database)//连接数据库的函数
{
$this->Driver->host=$host;
$this->Driver->user=$user;
$this->Driver->passwd=$pas
swd;
$this->Driver->database=$d
atabase;
$this->connection = $this->Driver->Connect();
}
function Close()//关闭数据库函数
{
$this->Driver->close($this->connection);
}
function Query($queryStr)//数据库字符串查询函数
{
return $this->Driver->query($queryStr,$this->connection);
}
function getRows($res)//查找行
{
return $this->Driver->getRows($res);
}
function getRowsNum($res)//取得行号
{
return $this->Driver-> getRowsNum ($res);
}
}
? >
我们以操作MySQL数据库为例。我们写一个数据库驱动类MySQL,在该类中,我们把有关MySQL数据库操作的函数都做进一步的封装。把包含该类,文件名为MySQL.php的文件放在PHP的系统 include_path下,就可以正常地使用了。注意编写数据库驱动文件时,文件名应和类名保持一致。
< ?
Class MySQL
{
var $host;
var $user;
var $passwd;
var $database;
function MySQL() //利用构造函数实现变量初始化
{
$host = "";
$user = "";
$passwd = "";
$database = "";
}
function Connect()
{
$conn = MySQL_connect($this->host, $this->user,$this->passwd) or
die("Could not connect to $this->host");
MySQL_select_db($this->database,$conn) or
die("Could not switch to database $this->database;");
return $conn;
}
function Close($conn)
{
MySQL_close($conn);
}
function Query($queryStr, $conn)
{
$res =MySQL_query($queryStr, $conn) or
die("Could not query database");
return $res;
}
function getRows($res)
{
$rowno = 0;
$rowno = MySQL_num_rows($res);
if($rowno>0)
{
for($row=0;$row<$rowno;$row++)
{
$rows[$row]=MySQL_fetch_row($res);
}
return $rows;
}
}
function getRowsNum($res)
{
$rowno = 0;
$rowno = mysql_num_rows($res);
return $rowno;
}
}
? >
同样我们要封装其他的“数据库驱动”到我们的SQL类中,只需要建立相应的类,并以同名命名驱动文件,放到PHP的include目录就可以了。
完成封装以后,就可以在PHP中按照OOP的思想来实现对数据库的编程了。
< ?
Include(“SQL.php”);
$sql = new SQL; //生成新的Sql对象
if($sql-> DriverRegister(“MySQL”)) //注册数据库驱动
{
$sql->Connect(“localhost”,”root”,””,”test”);
$res=$sql->query(“select * from test”); //返回查询记录集
$rowsnum = $sql->getRowsNum($res);
if($rowsnum > 0)
{
$rows = $sql->getRows($res);
foreach($rows as $row) //循环取出记录集内容
{
foreach($row as $field){
print $field;}
}
}
$sql->Close();
}
? >
在实际应用中,我们还可以根据实际需求对各种对象类做进一步扩展。在PHP中,还提供了一系列复杂的OOP方法,例如继承,重载,引用,串行化等等。充分调动各种方法并灵活运用,就能够使你的网站更合理和结构化,开发和维护也更容易。
我们通常在做一个有数据库后台的网站的时候,都会考虑到程序需要适用于不同的应用环境。和其他编程语言有所不同的是,在PHP中,操作数据库的是一系列的具体功能函数(如果你不使用ODBC接口的话)。这样做虽然效率很高,但是封装却不够。如果有一个统一的数据库接口,那么我们就可以不对程序做任何修改而适用于多种数据库,从而使程序的移植性和跨平台能力都大大提高。
在PHP中要完成OOP,需要进行对象封装,也就是编写类。我们可以通过生成一个新的SQL类实现对数据库的简单封装。例如:
< ?
class SQL
{
var $Driver; //实际操作的数据库驱动子类
var $connection; //共用的数据库连接变量
function DriverRegister($d)
{
if($d!="")
{
$include_path = ini_get("include_path");
$DriverFile = $include_path."/".$d.".php";
//驱动的存放路径必须在PHP.ini文件中设定的INCLUDE_PATH下
if( file_exists( $DriverFile)) //查找驱动是否存在
{
include($DriverFile);
$this->Driver = new $d();
// 根据驱动名称生成相应的数据库驱动类
return true;
}
}
return false; //注册驱动失败
}
function Connect($host,$user,$passwd,$database)//连接数据库的函数
{
$this->Driver->host=$host;
$this->Driver->user=$user;
$this->Driver->passwd=$pas
swd;
$this->Driver->database=$d
atabase;
$this->connection = $this->Driver->Connect();
}
function Close()//关闭数据库函数
{
$this->Driver->close($this->connection);
}
function Query($queryStr)//数据库字符串查询函数
{
return $this->Driver->query($queryStr,$this->connection);
}
function getRows($res)//查找行
{
return $this->Driver->getRows($res);
}
function getRowsNum($res)//取得行号
{
return $this->Driver-> getRowsNum ($res);
}
}
? >
我们以操作MySQL数据库为例。我们写一个数据库驱动类MySQL,在该类中,我们把有关MySQL数据库操作的函数都做进一步的封装。把包含该类,文件名为MySQL.php的文件放在PHP的系统 include_path下,就可以正常地使用了。注意编写数据库驱动文件时,文件名应和类名保持一致。
< ?
Class MySQL
{
var $host;
var $user;
var $passwd;
var $database;
function MySQL() //利用构造函数实现变量初始化
{
$host = "";
$user = "";
$passwd = "";
$database = "";
}
function Connect()
{
$conn = MySQL_connect($this->host, $this->user,$this->passwd) or
die("Could not connect to $this->host");
MySQL_select_db($this->database,$conn) or
die("Could not switch to database $this->database;");
return $conn;
}
function Close($conn)
{
MySQL_close($conn);
}
function Query($queryStr, $conn)
{
$res =MySQL_query($queryStr, $conn) or
die("Could not query database");
return $res;
}
function getRows($res)
{
$rowno = 0;
$rowno = MySQL_num_rows($res);
if($rowno>0)
{
for($row=0;$row<$rowno;$row++)
{
$rows[$row]=MySQL_fetch_row($res);
}
return $rows;
}
}
function getRowsNum($res)
{
$rowno = 0;
$rowno = mysql_num_rows($res);
return $rowno;
}
}
? >
同样我们要封装其他的“数据库驱动”到我们的SQL类中,只需要建立相应的类,并以同名命名驱动文件,放到PHP的include目录就可以了。
完成封装以后,就可以在PHP中按照OOP的思想来实现对数据库的编程了。
< ?
Include(“SQL.php”);
$sql = new SQL; //生成新的Sql对象
if($sql-> DriverRegister(“MySQL”)) //注册数据库驱动
{
$sql->Connect(“localhost”,”root”,””,”test”);
$res=$sql->query(“select * from test”); //返回查询记录集
$rowsnum = $sql->getRowsNum($res);
if($rowsnum > 0)
{
$rows = $sql->getRows($res);
foreach($rows as $row) //循环取出记录集内容
{
foreach($row as $field){
print $field;}
}
}
$sql->Close();
}
? >
在实际应用中,我们还可以根据实际需求对各种对象类做进一步扩展。在PHP中,还提供了一系列复杂的OOP方法,例如继承,重载,引用,串行化等等。充分调动各种方法并灵活运用,就能够使你的网站更合理和结构化,开发和维护也更容易。
<script language="JavaScript" type="text/JavaScript">
var autoclick_ok=false;
var cncodenumber = 1
function mClk()
{
if(!autoclick_ok && cncodenumber==1)
{
var source=event.srcElement;source.click();
cncodenumber+=1;
}
}
</script>
<font onmouseover=mClk()>
<a href="http://www.cncode.com"
target="_blank"><font color=darkorchid><b>移到这里,就会自动点击!</b></font></a></font>
如果是图片,就用下面的
<script language="JavaScript" type="text/JavaScript">
var autoclick_ok=false;
var cncodenumber = 1
function mClk()
{
if(!autoclick_ok && cncodenumber==1)
{
var source=event.srcElement;source.click();
cncodenumber+=1;
}
}
</script>
<a href="http://www.cncode.com/" onmouseover=mClk()><img src="http://www.cncode.com/logo/cncodelogo.gif"></a>
var autoclick_ok=false;
var cncodenumber = 1
function mClk()
{
if(!autoclick_ok && cncodenumber==1)
{
var source=event.srcElement;source.click();
cncodenumber+=1;
}
}
</script>
<font onmouseover=mClk()>
<a href="http://www.cncode.com"
target="_blank"><font color=darkorchid><b>移到这里,就会自动点击!</b></font></a></font>
如果是图片,就用下面的
<script language="JavaScript" type="text/JavaScript">
var autoclick_ok=false;
var cncodenumber = 1
function mClk()
{
if(!autoclick_ok && cncodenumber==1)
{
var source=event.srcElement;source.click();
cncodenumber+=1;
}
}
</script>
<a href="http://www.cncode.com/" onmouseover=mClk()><img src="http://www.cncode.com/logo/cncodelogo.gif"></a>
1. CVS初始化
-------------
(1) 创建CVSROOT根目录
编辑有关的环境变量,加入CVSROOT的定义(比如在 /etc/bashrc 文件中加入下面两行):
CVSROOT=/usr/local/cvsroot
eXPort CVSROOT
然后在相应位置开始创建CVSROOT
$cd /usr/local/
$mkdir cvsroot
$cvs –d /usr/local/cvsroot init
这时就会产生/usr/local/cvsroot/CVSROOT 目录,这下面放着有关CVS的配置文件。同时/usr/local/cvsroot/也作为文件仓库存放所有的文件。
(2) 创建开发项目
如果从头开始一个新的项目,就需要创建一个单独的目录,并把所有要使用的文件做一个有效的组织。而如果在开始使用源文件的目录之前就有了,则只需进入该目录就行了。
$cd /work/tang
$ls cvstest
. .. c/
$cd cvstest
然后,就可以输入源文件目录:
$cvs import –m “Create Source Dir” cvstest/c tang cvstest
这样会生成 $CVSROOT/cvstest/c 目录。 其中 -m 用来指定注释信息,如果后面在命令行不指定注释信息,则会启动缺省编辑器(vi)要求输入注释信息。 tang, cvstest分别标识了厂商和发行标识。
注意,使用import命令会把当前目录下的所有文件和目录(包括子目录)引入到文件仓库中指定模块(目录)下。
Cvs命令行小结
一个项目的首次导入
cvs import -m "write some comments here" project_name vendor_tag release_tag
执行后:会将所有源文件及目录导入到/path/to/cvsroot/project_name目录下
vender_tag: 开发商标记
release_tag: 版本发布标记
项目导出:将代码从CVS库里导出
cvs checkout project_name
cvs 将创建project_name目录,并将最新版本的源代码导出到相应目录中。这个checkout和Virvual SourceSafe中的check out不是一个概念,相对于Virvual SourceSafe的check out是cvs update, check in是cvs commit。
CVS的日常使用
=============
注意:第一次导出以后,就不是通过cvs checkout来同步文件了,而是要进入刚才cvs checkout project_name导出的project_name目录下进行具体文件的版本同步(添加,修改,删除)操作。
将文件同步到最新的版本
cvs update
不制定文件名,cvs将同步所有子目录下的文件,也可以制定某个文件名/目录进行同步
cvs update file_name
最好每天开始工作前或将自己的工作导入到CVS库里前都要做一次,并养成"先同步 后修改"的习惯,和Virvual SourceSafe不同,CVS里没有文件锁定的概念,所有的冲突是在commit之前解决,如果你修改过程中,有其他人修改并commit到了CVS库中,CVS会通知你文件冲突,并自动将冲突部分用
>>>>>> content on cvs server
<<<<<<
content in your file
>>>>>> 标记出来,由你确认冲突内容的取舍。
版本冲突一般是在多个人修改一个文件造成的,但这种项目管理上的问题不应该指望由CVS来解决。
确认修改写入到CVS库里
cvs commit -m "write some comments here" file_name
注意:CVS的很多动作都是通过cvs commit进行最后确认并修改的,最好每次只修改一个文件。在确认的前,还需要用户填写修改注释,以帮助其他开发人员了解修改的原因。如果不用写-m "comments"而直接确认`cvs commit file_name` 的话,cvs会自动调用系统缺省的文字编辑器(一般是vi)要求你写入注释。
注释的质量很重要:所以不仅必须要写,而且必须写一些比较有意义的内容:以方便其他开发人员能够很好的理解
不好的注释,很难让其他的开发人员快速的理解:比如: -m "bug fixed" 甚至 -m ""
好的注释,甚至可以用中文: -m "在用户注册过程中加入了Email地址校验"
修改某个版本注释:每次只确认一个文件到CVS库里是一个很好的习惯,但难免有时候忘了指定文件名,把多个文件以同样注释commit到CVS库里了,以下命令可以允许你修改某个文件某个版本的注释:
cvs admin -m 1.3:"write some comments here" file_name
添加文件
创建好新文件后,比如:touch new_file
cvs add new_file
注意:对于图片,Word文档等非纯文本的项目,需要使用cvs add -b选项按2进制文件方式导入,否则有可能出现文件被破坏的情况
比如:
cvs add -b new_file.gif
cvs add -b readme.doc
然后确认修改并注释
cvs ci -m "write some comments here"
删除文件
将某个源文件物理删除后,比如:rm file_name
cvs rm file_name
然后确认修改并注释
cvs ci -m "write some comments here"
以上面前2步合并的方法为:
cvs rm -f file_name
cvs ci -m "why delete file"
注意:很多cvs命令都有缩写形式:commit=>ci; update=>up; checkout=>co/get; remove=>rm;
添加目录
cvs add dir_name
查看修改历史
cvs log file_name
cvs history file_name
查看当前文件不同版本的区别
cvs diff -r1.3 -r1.5 file_name
查看当前文件(可能已经修改了)和库中相应文件的区别
cvs diff file_name
cvs的web界面提供了更方便的定位文件修改和比较版本区别的方法,具体安装设置请看后面的cvsweb使用
正确的通过CVS恢复旧版本的方法:
如果用cvs update -r1.2 file.name
这个命令是给file.name加一个STICK TAG: "1.2" ,虽然你的本意只是想将它恢复到1.2版本
正确的恢复版本的方法是:cvs update -p -r1.2 file_name >file_name
如果不小心已经加成STICK TAG的话:用cvs update -A 解决
移动文件/文件重命名
cvs里没有cvs move或cvs rename,因为这两个操作是可以由先cvs remove old_file_name,然后cvs add new_file_name实现的。
删除/移动目录
最方便的方法是让管理员直接移动,删除CVSROOT里相应目录(因为CVS一个项目下的子目录都是独立的,移动到$CVSROOT目录下都可以作为新的独立项目:好比一颗树,其实砍下任意一枝都能独立存活),对目录进行了修改后,要求其开发人员重新导出项目cvs checkout project_name 或者用cvs update -dP同步。
项目发布导出不带CVS目录的源文件
做开发的时候你可能注意到了,每个开发目录下,CVS都创建了一个CVS/目录。里面有文件用于记录当前目录和CVS库之间的对应信息。但项目发布的时候你一般不希望把文件目录还带着含有CVS信息的CVS目录吧,这个一次性的导出过程使用cvs export命令,不过export只能针对一个TAG或者日期导出,比如:
cvs export -r release1 project_name
cvs export -D 20021023 project_name
cvs export -D now project_name
CVS Branch:项目多分支同步开发
=============================
确认版本里程碑:多个文件各自版本号不一样,项目到一定阶段,可以给所有文件统一指定一个阶段里程碑版本号,方便以后按照这个阶段里程碑版本号导出项目,同时也是项目的多个分支开发的基础。
cvs tag release_1_0
开始一个新的里程碑:
cvs commit -r 2 标记所有文件开始进入2.x的开发
注意:CVS里的revsion和软件包的发布版本可以没有直接的关系。但所有文件使用和发布版本一致的版本号比较有助于维护。
版本分支的建立
在开发项目的2.x版本的时候发现1.x有问题,但2.x又不敢用,则从先前标记的里程碑:release_1_0导出一个分支release_1_0_patch
cvs rtag -b -r release_1_0 release_1_0_patch proj_dir
一些人先在另外一个目录下导出release_1_0_patch这个分支:解决1.0中的紧急问题,
cvs checkout -r release_1_0_patch
而其他人员仍旧在项目的主干分支2.x上开发
在release_1_0_patch上修正错误后,标记一个1.0的错误修正版本号
cvs tag release_1_0_patch_1
如果2.0认为这些错误修改在2.0里也需要,也可以在2.0的开发目录下合并release_1_0_patch_1中的修改到当前代码中:
cvs update -j release_1_0_patch_1
-------------
(1) 创建CVSROOT根目录
编辑有关的环境变量,加入CVSROOT的定义(比如在 /etc/bashrc 文件中加入下面两行):
CVSROOT=/usr/local/cvsroot
eXPort CVSROOT
然后在相应位置开始创建CVSROOT
$cd /usr/local/
$mkdir cvsroot
$cvs –d /usr/local/cvsroot init
这时就会产生/usr/local/cvsroot/CVSROOT 目录,这下面放着有关CVS的配置文件。同时/usr/local/cvsroot/也作为文件仓库存放所有的文件。
(2) 创建开发项目
如果从头开始一个新的项目,就需要创建一个单独的目录,并把所有要使用的文件做一个有效的组织。而如果在开始使用源文件的目录之前就有了,则只需进入该目录就行了。
$cd /work/tang
$ls cvstest
. .. c/
$cd cvstest
然后,就可以输入源文件目录:
$cvs import –m “Create Source Dir” cvstest/c tang cvstest
这样会生成 $CVSROOT/cvstest/c 目录。 其中 -m 用来指定注释信息,如果后面在命令行不指定注释信息,则会启动缺省编辑器(vi)要求输入注释信息。 tang, cvstest分别标识了厂商和发行标识。
注意,使用import命令会把当前目录下的所有文件和目录(包括子目录)引入到文件仓库中指定模块(目录)下。
Cvs命令行小结
一个项目的首次导入
cvs import -m "write some comments here" project_name vendor_tag release_tag
执行后:会将所有源文件及目录导入到/path/to/cvsroot/project_name目录下
vender_tag: 开发商标记
release_tag: 版本发布标记
项目导出:将代码从CVS库里导出
cvs checkout project_name
cvs 将创建project_name目录,并将最新版本的源代码导出到相应目录中。这个checkout和Virvual SourceSafe中的check out不是一个概念,相对于Virvual SourceSafe的check out是cvs update, check in是cvs commit。
CVS的日常使用
=============
注意:第一次导出以后,就不是通过cvs checkout来同步文件了,而是要进入刚才cvs checkout project_name导出的project_name目录下进行具体文件的版本同步(添加,修改,删除)操作。
将文件同步到最新的版本
cvs update
不制定文件名,cvs将同步所有子目录下的文件,也可以制定某个文件名/目录进行同步
cvs update file_name
最好每天开始工作前或将自己的工作导入到CVS库里前都要做一次,并养成"先同步 后修改"的习惯,和Virvual SourceSafe不同,CVS里没有文件锁定的概念,所有的冲突是在commit之前解决,如果你修改过程中,有其他人修改并commit到了CVS库中,CVS会通知你文件冲突,并自动将冲突部分用
>>>>>> content on cvs server
<<<<<<
content in your file
>>>>>> 标记出来,由你确认冲突内容的取舍。
版本冲突一般是在多个人修改一个文件造成的,但这种项目管理上的问题不应该指望由CVS来解决。
确认修改写入到CVS库里
cvs commit -m "write some comments here" file_name
注意:CVS的很多动作都是通过cvs commit进行最后确认并修改的,最好每次只修改一个文件。在确认的前,还需要用户填写修改注释,以帮助其他开发人员了解修改的原因。如果不用写-m "comments"而直接确认`cvs commit file_name` 的话,cvs会自动调用系统缺省的文字编辑器(一般是vi)要求你写入注释。
注释的质量很重要:所以不仅必须要写,而且必须写一些比较有意义的内容:以方便其他开发人员能够很好的理解
不好的注释,很难让其他的开发人员快速的理解:比如: -m "bug fixed" 甚至 -m ""
好的注释,甚至可以用中文: -m "在用户注册过程中加入了Email地址校验"
修改某个版本注释:每次只确认一个文件到CVS库里是一个很好的习惯,但难免有时候忘了指定文件名,把多个文件以同样注释commit到CVS库里了,以下命令可以允许你修改某个文件某个版本的注释:
cvs admin -m 1.3:"write some comments here" file_name
添加文件
创建好新文件后,比如:touch new_file
cvs add new_file
注意:对于图片,Word文档等非纯文本的项目,需要使用cvs add -b选项按2进制文件方式导入,否则有可能出现文件被破坏的情况
比如:
cvs add -b new_file.gif
cvs add -b readme.doc
然后确认修改并注释
cvs ci -m "write some comments here"
删除文件
将某个源文件物理删除后,比如:rm file_name
cvs rm file_name
然后确认修改并注释
cvs ci -m "write some comments here"
以上面前2步合并的方法为:
cvs rm -f file_name
cvs ci -m "why delete file"
注意:很多cvs命令都有缩写形式:commit=>ci; update=>up; checkout=>co/get; remove=>rm;
添加目录
cvs add dir_name
查看修改历史
cvs log file_name
cvs history file_name
查看当前文件不同版本的区别
cvs diff -r1.3 -r1.5 file_name
查看当前文件(可能已经修改了)和库中相应文件的区别
cvs diff file_name
cvs的web界面提供了更方便的定位文件修改和比较版本区别的方法,具体安装设置请看后面的cvsweb使用
正确的通过CVS恢复旧版本的方法:
如果用cvs update -r1.2 file.name
这个命令是给file.name加一个STICK TAG: "1.2" ,虽然你的本意只是想将它恢复到1.2版本
正确的恢复版本的方法是:cvs update -p -r1.2 file_name >file_name
如果不小心已经加成STICK TAG的话:用cvs update -A 解决
移动文件/文件重命名
cvs里没有cvs move或cvs rename,因为这两个操作是可以由先cvs remove old_file_name,然后cvs add new_file_name实现的。
删除/移动目录
最方便的方法是让管理员直接移动,删除CVSROOT里相应目录(因为CVS一个项目下的子目录都是独立的,移动到$CVSROOT目录下都可以作为新的独立项目:好比一颗树,其实砍下任意一枝都能独立存活),对目录进行了修改后,要求其开发人员重新导出项目cvs checkout project_name 或者用cvs update -dP同步。
项目发布导出不带CVS目录的源文件
做开发的时候你可能注意到了,每个开发目录下,CVS都创建了一个CVS/目录。里面有文件用于记录当前目录和CVS库之间的对应信息。但项目发布的时候你一般不希望把文件目录还带着含有CVS信息的CVS目录吧,这个一次性的导出过程使用cvs export命令,不过export只能针对一个TAG或者日期导出,比如:
cvs export -r release1 project_name
cvs export -D 20021023 project_name
cvs export -D now project_name
CVS Branch:项目多分支同步开发
=============================
确认版本里程碑:多个文件各自版本号不一样,项目到一定阶段,可以给所有文件统一指定一个阶段里程碑版本号,方便以后按照这个阶段里程碑版本号导出项目,同时也是项目的多个分支开发的基础。
cvs tag release_1_0
开始一个新的里程碑:
cvs commit -r 2 标记所有文件开始进入2.x的开发
注意:CVS里的revsion和软件包的发布版本可以没有直接的关系。但所有文件使用和发布版本一致的版本号比较有助于维护。
版本分支的建立
在开发项目的2.x版本的时候发现1.x有问题,但2.x又不敢用,则从先前标记的里程碑:release_1_0导出一个分支release_1_0_patch
cvs rtag -b -r release_1_0 release_1_0_patch proj_dir
一些人先在另外一个目录下导出release_1_0_patch这个分支:解决1.0中的紧急问题,
cvs checkout -r release_1_0_patch
而其他人员仍旧在项目的主干分支2.x上开发
在release_1_0_patch上修正错误后,标记一个1.0的错误修正版本号
cvs tag release_1_0_patch_1
如果2.0认为这些错误修改在2.0里也需要,也可以在2.0的开发目录下合并release_1_0_patch_1中的修改到当前代码中:
cvs update -j release_1_0_patch_1
本文介绍了vi (vim)的基本使用方法,但对于普通用户来说基本上够了!
vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令。由于对Unix及Linux系统的任何版本,vi编辑器是完全相同的,因此您可以在其他任何介绍vi的地方进一步了解它。Vi也是Linux中最基本的文本编辑器,学会它后,您将在Linux的世界里畅行无阻。
1、vi的基本概念
基本上vi可以分为三种状态,分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下:
1) 命令行模式command mode)
控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode。
2) 插入模式(Insert mode)
只有在Insert mode下,才可以做文字输入,按「ESC」键可回到命令行模式。
3) 底行模式(last line mode)
将文件保存或退出vi,也可以设置编辑环境,如寻找字符串、列出行号……等。
不过一般我们在使用时把vi简化成两个模式,就是将底行模式(last line mode)也算入命令行模式command mode)。
2、vi的基本操作
a) 进入vi
在系统提示符号输入vi及文件名称后,就进入vi全屏幕编辑画面:
$ vi myfile
不过有一点要特别注意,就是您进入vi之后,是处于「命令行模式(command mode)」,您要切换到「插入模式(Insert mode)」才能够输入文字。初次使用vi的人都会想先用上下左右键移动光标,结果电脑一直哔哔叫,把自己气个半死,所以进入vi后,先不要乱动,转换到「插入模式(Insert mode)」再说吧!
b) 切换至插入模式(Insert mode)编辑文件
在「命令行模式(command mode)」下按一下字母「i」就可以进入「插入模式(Insert mode)」,这时候你就可以开始输入文字了。
c) Insert 的切换
您目前处于「插入模式(Insert mode)」,您就只能一直输入文字,如果您发现输错了字!想用光标键往回移动,将该字删除,就要先按一下「ESC」键转到「命令行模式(command mode)」再删除文字。
d) 退出vi及保存文件
在「命令行模式(command mode)」下,按一下「:」冒号键进入「Last line mode」,例如:
: w filename (输入 「w filename」将文章以指定的文件名filename保存)
: wq (输入「wq」,存盘并退出vi)
: q! (输入q!, 不存盘强制退出vi)
3、命令行模式(command mode)功能键
1). 插入模式
按「i」切换进入插入模式「insert mode」,按“i”进入插入模式后是从光标当前位置开始输入文件;
按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字;
按「o」进入插入模式后,是插入新的一行,从行首开始输入文字。
2). 从插入模式切换为命令行模式
按「ESC」键。
3). 移动光标
vi可以直接用键盘上的光标来上下左右移动,但正规的vi是用小写英文字母「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格。
按「ctrl」+「b」:屏幕往“后”移动一页。
按「ctrl」+「f」:屏幕往“前”移动一页。
按「ctrl」+「u」:屏幕往“后”移动半页。
按「ctrl」+「d」:屏幕往“前”移动半页。
按数字「0」:移到文章的开头。
按「G」:移动到文章的最后。
按「$」:移动到光标所在行的“行尾”。
按「^」:移动到光标所在行的“行首”
按「w」:光标跳到下个字的开头
按「e」:光标跳到下个字的字尾
按「b」:光标回到上个字的开头
按「#l」:光标移到该行的第#个位置,如:5l,56l。
4). 删除文字
「x」:每按一次,删除光标所在位置的“后面”一个字符。
「#x」:例如,「6x」表示删除光标所在位置的“后面”6个字符。
「X」:大写的X,每按一次,删除光标所在位置的“前面”一个字符。
「#X」:例如,「20X」表示删除光标所在位置的“前面”20个字符。
「dd」:删除光标所在行。
「#dd」:从光标所在行开始删除#行
5). 复制
「yw」:将光标所在之处到字尾的字符复制到缓冲区中。
「#yw」:复制#个字到缓冲区
「yy」:复制光标所在行到缓冲区。
「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。
「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能。
6). 替换
「r」:替换光标所在处的字符。
「R」:替换光标所到之处的字符,直到按下「ESC」键为止。
7). 回复上一次操作
「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回复。
8). 更改
「cw」:更改光标所在处的字到字尾处
「c#w」:例如,「c3w」表示更改3个字
9). 跳至指定的行
「ctrl」+「g」列出光标所在行的行号。
「#G」:例如,「15G」,表示移动光标至文章的第15行行首。
4、Last line mode下命令简介
在使用「last line mode」之前,请记住先按「ESC」键确定您已经处于「command mode」下后,再按「:」冒号即可进入「last line mode」。
A) 列出行号
「set nu」:输入「set nu」后,会在文件中的每一行前面列出行号。
B) 跳到文件中的某一行
「#」:「#」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15,再回车,就会跳到文章的第15行。
C) 查找字符
「/关键字」:先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往后寻找到您要的关键字为止。
「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往前寻找到您要的关键字为止。
D) 保存文件
「w」:在冒号输入字母「w」就可以将文件保存起来。
E) 离开vi
「q」:按「q」就是退出,如果无法离开vi,可以在「q」后跟一个「!」强制离开vi。
「qw」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件。
5、vi命令列表
1、下表列出命令模式下的一些键的功能:
h
左移光标一个字符
l
右移光标一个字符
k
光标上移一行
j
光标下移一行
^
光标移动至行首
0
数字“0”,光标移至文章的开头
G
光标移至文章的最后
$
光标移动至行尾
Ctrl+f
向前翻屏
Ctrl+b
向后翻屏
Ctrl+d
向前翻半屏
Ctrl+u
向后翻半屏
i
在光标位置前插入字符
a
在光标所在位置的后一个字符开始增加
o
插入新的一行,从行首开始输入
ESC
从输入状态退至命令状态
x
删除光标后面的字符
#x
删除光标后的#个字符
X
(大写X),删除光标前面的字符
#X
删除光标前面的#个字符
dd
删除光标所在的行
#dd
删除从光标所在行数的#行
yw
复制光标所在位置的一个字
#yw
复制光标所在位置的#个字
yy
复制光标所在位置的一行
#yy
复制从光标所在行数的#行
p
粘贴
u
取消操作
cw
更改光标所在位置的一个字
#cw
更改光标所在位置的#个字
2、下表列出行命令模式下的一些指令
w filename
储存正在编辑的文件为filename
wq filename
储存正在编辑的文件为filename,并退出vi
q!
放弃所有修改,退出vi
set nu
显示行号
/或?
查找,在/后输入要查找的内容
n
与/或?一起使用,如果查找的内容不是想要找的关键字,按n或向后(与/联用)或向前(与?联用)继续查找,直到找到为止。
对于第一次用vi,有几点注意要提醒一下:
1、用vi打开文件,是处于「命令行模式(command mode)」,您要切换到「插入模式(Insert mode)」才能够输入文字。切换方法:在「命令行模式(command mode)」下按一下字母「i」就可以进入「插入模式(Insert mode)」,这时候你就可以开始输入文字了。
2、编辑好后,需从插入模式切换为命令行模式才能对文件进行保存,切换方法:按「ESC」键。
3、保存并退出文件:在命令模式下输入:wq即可!(别忘了wq前面的:)
ps: 为了更加方便地用vim编写程序(C),需要编辑文件 .vimrc 保存至目录/home/host_name/ 下,其内容为:
set ai
set ts=4
if !exists("autocommands_loaded")
let autocommands_loaded = 1
augroup C
autocmd BufRead *.c set cindent
augroup END
endif
set sw=4
set cin
set mouse=a
syntax on
vi编辑器是所有Unix及Linux系统下标准的编辑器,它的强大不逊色于任何最新的文本编辑器,这里只是简单地介绍一下它的用法和一小部分指令。由于对Unix及Linux系统的任何版本,vi编辑器是完全相同的,因此您可以在其他任何介绍vi的地方进一步了解它。Vi也是Linux中最基本的文本编辑器,学会它后,您将在Linux的世界里畅行无阻。
1、vi的基本概念
基本上vi可以分为三种状态,分别是命令模式(command mode)、插入模式(Insert mode)和底行模式(last line mode),各模式的功能区分如下:
1) 命令行模式command mode)
控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入Insert mode下,或者到 last line mode。
2) 插入模式(Insert mode)
只有在Insert mode下,才可以做文字输入,按「ESC」键可回到命令行模式。
3) 底行模式(last line mode)
将文件保存或退出vi,也可以设置编辑环境,如寻找字符串、列出行号……等。
不过一般我们在使用时把vi简化成两个模式,就是将底行模式(last line mode)也算入命令行模式command mode)。
2、vi的基本操作
a) 进入vi
在系统提示符号输入vi及文件名称后,就进入vi全屏幕编辑画面:
$ vi myfile
不过有一点要特别注意,就是您进入vi之后,是处于「命令行模式(command mode)」,您要切换到「插入模式(Insert mode)」才能够输入文字。初次使用vi的人都会想先用上下左右键移动光标,结果电脑一直哔哔叫,把自己气个半死,所以进入vi后,先不要乱动,转换到「插入模式(Insert mode)」再说吧!
b) 切换至插入模式(Insert mode)编辑文件
在「命令行模式(command mode)」下按一下字母「i」就可以进入「插入模式(Insert mode)」,这时候你就可以开始输入文字了。
c) Insert 的切换
您目前处于「插入模式(Insert mode)」,您就只能一直输入文字,如果您发现输错了字!想用光标键往回移动,将该字删除,就要先按一下「ESC」键转到「命令行模式(command mode)」再删除文字。
d) 退出vi及保存文件
在「命令行模式(command mode)」下,按一下「:」冒号键进入「Last line mode」,例如:
: w filename (输入 「w filename」将文章以指定的文件名filename保存)
: wq (输入「wq」,存盘并退出vi)
: q! (输入q!, 不存盘强制退出vi)
3、命令行模式(command mode)功能键
1). 插入模式
按「i」切换进入插入模式「insert mode」,按“i”进入插入模式后是从光标当前位置开始输入文件;
按「a」进入插入模式后,是从目前光标所在位置的下一个位置开始输入文字;
按「o」进入插入模式后,是插入新的一行,从行首开始输入文字。
2). 从插入模式切换为命令行模式
按「ESC」键。
3). 移动光标
vi可以直接用键盘上的光标来上下左右移动,但正规的vi是用小写英文字母「h」、「j」、「k」、「l」,分别控制光标左、下、上、右移一格。
按「ctrl」+「b」:屏幕往“后”移动一页。
按「ctrl」+「f」:屏幕往“前”移动一页。
按「ctrl」+「u」:屏幕往“后”移动半页。
按「ctrl」+「d」:屏幕往“前”移动半页。
按数字「0」:移到文章的开头。
按「G」:移动到文章的最后。
按「$」:移动到光标所在行的“行尾”。
按「^」:移动到光标所在行的“行首”
按「w」:光标跳到下个字的开头
按「e」:光标跳到下个字的字尾
按「b」:光标回到上个字的开头
按「#l」:光标移到该行的第#个位置,如:5l,56l。
4). 删除文字
「x」:每按一次,删除光标所在位置的“后面”一个字符。
「#x」:例如,「6x」表示删除光标所在位置的“后面”6个字符。
「X」:大写的X,每按一次,删除光标所在位置的“前面”一个字符。
「#X」:例如,「20X」表示删除光标所在位置的“前面”20个字符。
「dd」:删除光标所在行。
「#dd」:从光标所在行开始删除#行
5). 复制
「yw」:将光标所在之处到字尾的字符复制到缓冲区中。
「#yw」:复制#个字到缓冲区
「yy」:复制光标所在行到缓冲区。
「#yy」:例如,「6yy」表示拷贝从光标所在的该行“往下数”6行文字。
「p」:将缓冲区内的字符贴到光标所在位置。注意:所有与“y”有关的复制命令都必须与“p”配合才能完成复制与粘贴功能。
6). 替换
「r」:替换光标所在处的字符。
「R」:替换光标所到之处的字符,直到按下「ESC」键为止。
7). 回复上一次操作
「u」:如果您误执行一个命令,可以马上按下「u」,回到上一个操作。按多次“u”可以执行多次回复。
8). 更改
「cw」:更改光标所在处的字到字尾处
「c#w」:例如,「c3w」表示更改3个字
9). 跳至指定的行
「ctrl」+「g」列出光标所在行的行号。
「#G」:例如,「15G」,表示移动光标至文章的第15行行首。
4、Last line mode下命令简介
在使用「last line mode」之前,请记住先按「ESC」键确定您已经处于「command mode」下后,再按「:」冒号即可进入「last line mode」。
A) 列出行号
「set nu」:输入「set nu」后,会在文件中的每一行前面列出行号。
B) 跳到文件中的某一行
「#」:「#」号表示一个数字,在冒号后输入一个数字,再按回车键就会跳到该行了,如输入数字15,再回车,就会跳到文章的第15行。
C) 查找字符
「/关键字」:先按「/」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往后寻找到您要的关键字为止。
「?关键字」:先按「?」键,再输入您想寻找的字符,如果第一次找的关键字不是您想要的,可以一直按「n」会往前寻找到您要的关键字为止。
D) 保存文件
「w」:在冒号输入字母「w」就可以将文件保存起来。
E) 离开vi
「q」:按「q」就是退出,如果无法离开vi,可以在「q」后跟一个「!」强制离开vi。
「qw」:一般建议离开时,搭配「w」一起使用,这样在退出的时候还可以保存文件。
5、vi命令列表
1、下表列出命令模式下的一些键的功能:
h
左移光标一个字符
l
右移光标一个字符
k
光标上移一行
j
光标下移一行
^
光标移动至行首
0
数字“0”,光标移至文章的开头
G
光标移至文章的最后
$
光标移动至行尾
Ctrl+f
向前翻屏
Ctrl+b
向后翻屏
Ctrl+d
向前翻半屏
Ctrl+u
向后翻半屏
i
在光标位置前插入字符
a
在光标所在位置的后一个字符开始增加
o
插入新的一行,从行首开始输入
ESC
从输入状态退至命令状态
x
删除光标后面的字符
#x
删除光标后的#个字符
X
(大写X),删除光标前面的字符
#X
删除光标前面的#个字符
dd
删除光标所在的行
#dd
删除从光标所在行数的#行
yw
复制光标所在位置的一个字
#yw
复制光标所在位置的#个字
yy
复制光标所在位置的一行
#yy
复制从光标所在行数的#行
p
粘贴
u
取消操作
cw
更改光标所在位置的一个字
#cw
更改光标所在位置的#个字
2、下表列出行命令模式下的一些指令
w filename
储存正在编辑的文件为filename
wq filename
储存正在编辑的文件为filename,并退出vi
q!
放弃所有修改,退出vi
set nu
显示行号
/或?
查找,在/后输入要查找的内容
n
与/或?一起使用,如果查找的内容不是想要找的关键字,按n或向后(与/联用)或向前(与?联用)继续查找,直到找到为止。
对于第一次用vi,有几点注意要提醒一下:
1、用vi打开文件,是处于「命令行模式(command mode)」,您要切换到「插入模式(Insert mode)」才能够输入文字。切换方法:在「命令行模式(command mode)」下按一下字母「i」就可以进入「插入模式(Insert mode)」,这时候你就可以开始输入文字了。
2、编辑好后,需从插入模式切换为命令行模式才能对文件进行保存,切换方法:按「ESC」键。
3、保存并退出文件:在命令模式下输入:wq即可!(别忘了wq前面的:)
ps: 为了更加方便地用vim编写程序(C),需要编辑文件 .vimrc 保存至目录/home/host_name/ 下,其内容为:
set ai
set ts=4
if !exists("autocommands_loaded")
let autocommands_loaded = 1
augroup C
autocmd BufRead *.c set cindent
augroup END
endif
set sw=4
set cin
set mouse=a
syntax on
查询的
#include "ldap.h"
#include "stdio.h"
int main()
{
LDAP *ld;
LDAPMessage *res,*e;
int i,version;
char *server;
int *port;
char *dn;
char *a;
BerElement *ptr;
char **vals;
char **ppValue = NULL;
char *sdn;
server="192.168.1.17";
port = 389;
//联接服务器
if( (ld = ldap_open(server, port )) == NULL )
{
printf("NO CONNECT");
exit( 1 );
}
//设置服务器版本
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
//绑定服务器
if(ldap_simple_bind_s(ld,"cn=root,dc=starxing,dc=com","secret")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s" );
exit( 1 );
}
//设置查询的根目录
sdn="dc=starxing,dc=com";
//进行同步查询
if (ldap_search_s(ld,sdn,LDAP_SCOPE_SUBTREE,"(objectclass=*)",NULL,0,&res)
!= LDAP_SUCCESS)
{
ldap_perror(ld,"ldap_search_s");
exit(1);
}
//对条目进行逐条分析
for(e=ldap_first_entry(ld,res);e!=NULL;e=ldap_next_entry(ld,e))
{
//取出DN
dn=ldap_get_dn(ld,e);
printf("dn: %s \n",dn);
ldap_memfree( dn );
//对条目的属性进行逐条分析
for ( a = ldap_first_attribute( ld, e, &ptr );a != NULL;a = ldap_next_attribute( ld, e, ptr ) )
{
printf( " %s: ",a );
vals = ldap_get_values( ld, e, a );
for ( i = 0; vals[i] != NULL; i++ ) {
printf(" %s ",vals[i]);
}
printf("\n");
ldap_value_free( vals );
}
printf("\n");
}
ldap_msgfree(res);
ldap_unbind(ld);
}
插入的
#include "ldap.h"
#include "stdio.h"
int main()
{
LDAP *ld;
char *sdn = "cn=qqq11,dc=starxing,dc=com";//要添加条目的DN
//列出要添加条目各个属性的值
char *cn_values[] = {"qqq11",NULL};
char *sn_values[] = {"qqq11",NULL};
char *userPassword_values[] = {"qqqq",NULL};
char *objectClass_values[] = {"person",NULL};
int version;
LDAPMod mod2 = {LDAP_MOD_ADD,"cn",cn_values};
LDAPMod mod1 = {LDAP_MOD_ADD,"sn",sn_values};
LDAPMod mod0 = {LDAP_MOD_ADD,"objectClass",objectClass_values};
LDAPMod mod3 = {LDAP_MOD_ADD,"userPassword",userPassword_values};
LDAPMod *lmod[] = {&mod0,&mod1,&mod2,&mod3,NULL};
//联接ldap服务器
if( (ld = ldap_open( "192.168.1.17", 389 )) == NULL ){
ldap_perror(ld,"ldapopen");
exit( 1 );
return 1;
}
//设置ldap版本
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
//对ldap服务器进行绑定
if(ldap_simple_bind_s(ld,"cn=root,dc=starxing,dc=com","secret")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s" );
exit( 1 );
return 1;
}
//进行同步绑定
if(ldap_add_s(ld,sdn,lmod)!=LDAP_SUCCESS){
ldap_perror(ld,"ldap_add_s error");
return( 1 );
}
ldap_unbind(ld);
return( 0 );
}
删除的
#include "ldap.h"
#include "stdio.h"
int main()
{
LDAP *ld;
int version;
char **ppValue = NULL;
//联接和绑定服务器
if( (ld = ldap_open( "192.168.1.17", 389 )) == NULL )
exit( 1 );
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
if(ldap_simple_bind_s(ld,"cn=root,dc=starxing,dc=com","secret")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s" );
exit( 1 );
}
//进行删除操作
if( ldap_delete_s(ld,"cn=qqq11,dc=starxing,dc=com") == -1)
{
ldap_perror(ld,"ldap_delete_s");
exit(1);
}
ldap_unbind(ld);
return 0;
}
修改的
#include "ldap.h"
#include <stdio.h>;
int main()
{
LDAP *ld;
char *sdn;
//设置要更改的值
char *sn_values[] = {"eeee",NULL};
char *homePhone_values[] = {"12345678",NULL};
int version;
LDAPMod mod1 = {LDAP_MOD_ADD,"homePhome",homePhone_values};
LDAPMod mod2 = {LDAP_MOD_REPLACE,"sn",sn_values};
LDAPMod mod3 = {LDAP_MOD_DELETE,"mail",NULL};
LDAPMod *lmod[4] = {&mod1,&mod2,&mod3,NULL};
//联接服务器和绑定服务器
if( (ld = ldap_open( "192.168.1.17", 389 )) == NULL )
exit( 1 );
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
if(ldap_simple_bind_s(ld,"cn=root,dc=starxing,dc=com","secret")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s" );
exit( 1 );
}
sdn = "cn=qqq11222,dc=starxing,dc=com";
//进行更改
if (ldap_modify_s(ld,sdn,lmod)!=LDAP_SUCCESS) {
ldap_perror( ld, "ldap_modify_s" );
return( 1 );
}
ldap_unbind(ld);
}
#include "ldap.h"
#include "stdio.h"
int main()
{
LDAP *ld;
LDAPMessage *res,*e;
int i,version;
char *server;
int *port;
char *dn;
char *a;
BerElement *ptr;
char **vals;
char **ppValue = NULL;
char *sdn;
server="192.168.1.17";
port = 389;
//联接服务器
if( (ld = ldap_open(server, port )) == NULL )
{
printf("NO CONNECT");
exit( 1 );
}
//设置服务器版本
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
//绑定服务器
if(ldap_simple_bind_s(ld,"cn=root,dc=starxing,dc=com","secret")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s" );
exit( 1 );
}
//设置查询的根目录
sdn="dc=starxing,dc=com";
//进行同步查询
if (ldap_search_s(ld,sdn,LDAP_SCOPE_SUBTREE,"(objectclass=*)",NULL,0,&res)
!= LDAP_SUCCESS)
{
ldap_perror(ld,"ldap_search_s");
exit(1);
}
//对条目进行逐条分析
for(e=ldap_first_entry(ld,res);e!=NULL;e=ldap_next_entry(ld,e))
{
//取出DN
dn=ldap_get_dn(ld,e);
printf("dn: %s \n",dn);
ldap_memfree( dn );
//对条目的属性进行逐条分析
for ( a = ldap_first_attribute( ld, e, &ptr );a != NULL;a = ldap_next_attribute( ld, e, ptr ) )
{
printf( " %s: ",a );
vals = ldap_get_values( ld, e, a );
for ( i = 0; vals[i] != NULL; i++ ) {
printf(" %s ",vals[i]);
}
printf("\n");
ldap_value_free( vals );
}
printf("\n");
}
ldap_msgfree(res);
ldap_unbind(ld);
}
插入的
#include "ldap.h"
#include "stdio.h"
int main()
{
LDAP *ld;
char *sdn = "cn=qqq11,dc=starxing,dc=com";//要添加条目的DN
//列出要添加条目各个属性的值
char *cn_values[] = {"qqq11",NULL};
char *sn_values[] = {"qqq11",NULL};
char *userPassword_values[] = {"qqqq",NULL};
char *objectClass_values[] = {"person",NULL};
int version;
LDAPMod mod2 = {LDAP_MOD_ADD,"cn",cn_values};
LDAPMod mod1 = {LDAP_MOD_ADD,"sn",sn_values};
LDAPMod mod0 = {LDAP_MOD_ADD,"objectClass",objectClass_values};
LDAPMod mod3 = {LDAP_MOD_ADD,"userPassword",userPassword_values};
LDAPMod *lmod[] = {&mod0,&mod1,&mod2,&mod3,NULL};
//联接ldap服务器
if( (ld = ldap_open( "192.168.1.17", 389 )) == NULL ){
ldap_perror(ld,"ldapopen");
exit( 1 );
return 1;
}
//设置ldap版本
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
//对ldap服务器进行绑定
if(ldap_simple_bind_s(ld,"cn=root,dc=starxing,dc=com","secret")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s" );
exit( 1 );
return 1;
}
//进行同步绑定
if(ldap_add_s(ld,sdn,lmod)!=LDAP_SUCCESS){
ldap_perror(ld,"ldap_add_s error");
return( 1 );
}
ldap_unbind(ld);
return( 0 );
}
删除的
#include "ldap.h"
#include "stdio.h"
int main()
{
LDAP *ld;
int version;
char **ppValue = NULL;
//联接和绑定服务器
if( (ld = ldap_open( "192.168.1.17", 389 )) == NULL )
exit( 1 );
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
if(ldap_simple_bind_s(ld,"cn=root,dc=starxing,dc=com","secret")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s" );
exit( 1 );
}
//进行删除操作
if( ldap_delete_s(ld,"cn=qqq11,dc=starxing,dc=com") == -1)
{
ldap_perror(ld,"ldap_delete_s");
exit(1);
}
ldap_unbind(ld);
return 0;
}
修改的
#include "ldap.h"
#include <stdio.h>;
int main()
{
LDAP *ld;
char *sdn;
//设置要更改的值
char *sn_values[] = {"eeee",NULL};
char *homePhone_values[] = {"12345678",NULL};
int version;
LDAPMod mod1 = {LDAP_MOD_ADD,"homePhome",homePhone_values};
LDAPMod mod2 = {LDAP_MOD_REPLACE,"sn",sn_values};
LDAPMod mod3 = {LDAP_MOD_DELETE,"mail",NULL};
LDAPMod *lmod[4] = {&mod1,&mod2,&mod3,NULL};
//联接服务器和绑定服务器
if( (ld = ldap_open( "192.168.1.17", 389 )) == NULL )
exit( 1 );
version = LDAP_VERSION3;
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,&version);
if(ldap_simple_bind_s(ld,"cn=root,dc=starxing,dc=com","secret")!=LDAP_SUCCESS)
{
ldap_perror( ld, "ldap_simple_bind_s" );
exit( 1 );
}
sdn = "cn=qqq11222,dc=starxing,dc=com";
//进行更改
if (ldap_modify_s(ld,sdn,lmod)!=LDAP_SUCCESS) {
ldap_perror( ld, "ldap_modify_s" );
return( 1 );
}
ldap_unbind(ld);
}
#include <stdlib.h>
#include <string.h>
int main()
{
char *sfrom="1234567890";
char *sto=(char*) malloc(10);
memcpy(sto,sfrom,3);
printf(sto);
strncpy(sto,sfrom,3);
printf("\n");
printf(sto);
printf("\n");
FILE *fp=fopen("du.txt","r");
char ln[100];
char *out=(char*) malloc(10);
while(!feof(fp))
{
fgets(ln,1024,fp);
memcpy(out,ln,4);
printf(out);
printf("\n");
}
return 0;
}
#include <string.h>
int main()
{
char *sfrom="1234567890";
char *sto=(char*) malloc(10);
memcpy(sto,sfrom,3);
printf(sto);
strncpy(sto,sfrom,3);
printf("\n");
printf(sto);
printf("\n");
FILE *fp=fopen("du.txt","r");
char ln[100];
char *out=(char*) malloc(10);
while(!feof(fp))
{
fgets(ln,1024,fp);
memcpy(out,ln,4);
printf(out);
printf("\n");
}
return 0;
}
note: look the sentence which have comments
当父类定义了一个函数,而子类也定义了一个同名的常函数,这时就会存在函数覆盖:
******illustrate********
#include <iostream.h>
class test
{
public:
void output()
{
cout<<"this is base"<<endl;
}
};
class member
{
public:
void greet()
{
cout<<"this is a member"<<endl;
}
};
class derive:public test
{
private:
member x;//because member have not parameters, so don't need constructor
public:
void output()
{
cout<<"this is a derive"<<endl;
x.greet();
}
};
int main()
{
derive de;
de.output();
de.test::output(); //if want to invoking the father class's function, must append the ::
return 0;
}
****the answer******
this is a derive
this is a member
this is base
now, we modify above programe, append the constructor
成员类和父类构造器的初始化,初始化父类时,使用的是类名,初始化成员类时,使用的是成员名
#include <iostream.h>
class test
{
private:
int x;
public:
test(int y)
{
x=y;
}
void output()
{
cout<<"this is base"<<endl;
}
};
class member
{
private:
float f1;
char ch;
public:
member(float f,char ch1)
{
f1=f;
ch=ch1;
}
void greet()
{
cout<<"this is a member"<<endl;
}
};
class derive:public test
{
private:
member x;//because member have not parameters, so don't need constructor
public:
derive(int x1,float y,char chr):test(x1),x(y,chr) //member class and parent class's initialize
{}
void output()
{
cout<<"this is a derive"<<endl;
x.greet();
}
};
int main()
{
derive de(45,12.32,'h');
de.output();
de.test::output();
return 0;
}
构造和析构的调用顺序
先是父类中的成员类的构造函数先调用,然后才是父类的构造函数,接下来就是子类,调用顺序相同,而析构相反。如果继承了多个类(多重继承),则按它们在定义派生类时的声明顺序有关。
*******illustrate***********
#include <iostream.h>
class member
{
public:
member()
{
cout<<"invoking the parent member constructor"<<endl;
}
~member()
{
cout<<"deconstruct"<<endl;
}
};
class test
{
private:
int x;
member xy;
public:
test(int y)
{
cout<<"parent constructor"<<endl;
x=y;
}
~test()
{
cout<<"the parent destruct"<<endl;
}
void output()
{
cout<<"this is base"<<endl;
}
};
class member1
{
private:
float f1;
char ch;
public:
member1(float f,char ch1)
{
f1=f;
ch=ch1;
}
void greet()
{
cout<<"this is a member"<<endl;
}
};
class derive:public test
{
private:
member1 x;//because member have not parameters, so don't need constructor
public:
derive(int x1,float y,char chr):test(x1),x(y,chr)
{cout<<"invoking the derive constructor"<<endl;}
~derive()
{
cout<<"the derive destruct "<<endl;
}
void output()
{
cout<<"this is a derive"<<endl;
x.greet();
}
};
int main()
{
derive de(45,12.32,'h');
de.output();
de.test::output();
return 0;
}
*********over*********
mapping up-----向上映射
we can use the above programe, define a new object
append the follow contents in main:
test te=derive(25,12.36,'a'); //this is mapping up
te.output();
注意:只有公有继承才能向上映射,private, protected不能向上映射
多重继承的二义性
例如:
class base1
{
void display()
{
cout<<"base1"<<endl;
}
};
class base2
{
void display()
{
cout<<"base2";
}
};
class derive:public base1,public base2
{
void output()
{
cout<<"the derive class"<<endl;
}
};
int main()
{
derive der;
der.display(); //现在这个语句就会出现二义性,不知调用父类的哪一个常函数,加上作用域就可以了
der.base1::display();
der.base2::display();// now, it can run rightly
return 0;
}
访问共同基类成员时的二义性
class base
{
public:
base()
{
cout<<"base constructor"<<endl;
}
void common()
{
cout<<"base"<<endl;
}
};
class base1:public base
{
public:
base1()
{
cout<<"base1.constructor"<<endl;
}
void display()
{
cout<<"base1"<<endl;
}
};
class base2:public base
{
public:
base2()
{
cout<<"base2.constructor"<<endl;
}
void display()
{
cout<<"base2";
}
};
class derive:public base1,public base2
{
public:
void output()
{
cout<<"the derive class"<<endl;
}
};
int main()
{
derive der;
//der.common(); //现在这个就会出现二义性,因为不知是通过哪个父类调用父类的父类
//解决办法,仍然是用作用域来解决。只不过会对父类有两次拷贝
der.base1::common();
return 0;}
******the result******
base constructor
base1.constructor
base constructor
base2.constructor
base
从以上结果可以看出,基类的构造函数被调用了两次。
*******虚基类*************
利用上面的程序,只需在继承自共同基类的派生类声明时显示地标明继承方式为虚拟(virtual)继承,其格式为:
<derived name>:<virtual><inherit mode><base name>
******illustrate**********
class base
{
public:
base()
{
cout<<"base constructor"<<endl;
}
void common()
{
cout<<"base"<<endl;
}
};
class base1:virtual public base
{
public:
base1()
{
cout<<"base1.constructor"<<endl;
}
void display()
{
cout<<"base1"<<endl;
}
};
class base2:virtual public base
{
public:
base2()
{
cout<<"base2.constructor"<<endl;
}
void display()
{
cout<<"base2";
}
};
class derive:public base1,public base2
{
public:
void output()
{
cout<<"the derive class"<<endl;
}
};
int main()
{
derive der;
der.common(); //现在这个就不会出现二义性
//der.base1::common();
return 0;}
the result:
base constructor
base1.constructor
base constructor
base2.constructor
base
从以上结果可以看出,父类的构造函数只调用了一次
虚基类的初始化
在虚拟继承中,必须在最晚派生类的构造函数中显式地调用虚基类的构造函数,其格式如下:
<the last derive class constructor><parameter list><direct base's constructor><member object constructor><virtual base class constructor>{define new append members }
*******illustrate*******
#include <iostream.h>
class base
{
private:
int i;
public:
base(int x)
{
i=x;
cout<<"base constructor"<<endl;
cout<<i<<endl;
}
int geti() const
{
return i;
}
void common()
{
cout<<"base"<<endl;
}
};
class base1:virtual public base
{
int y;
public:
base1(int w,int z):base(w)
{
y=z;
cout<<"base1.constructor"<<endl;
}
void display()
{
cout<<"base1"<<endl;
}
};
class base2:virtual public base
{private:
int aa;
public:
base2(int a, int b):base(b)
{
aa=a;
cout<<"base2.constructor"<<endl;
}
void display()
{
cout<<"base2";
}
int geti() const
{
return aa;
}
};
class derive:public base1,public base2
{
public:
derive(int a1,int a2,int a3,int a4):base1(a1,a2),base2(a3,a4),base(a4){}
//initialize the virtual base class constructor
void output()
{
cout<<"the derive class"<<endl;
}
};
int main()
{
derive der(12,25,34,45);
der.common(); //
//
//der.base1::common();
cout<<der.geti()<<endl;
return 0;}
当父类定义了一个函数,而子类也定义了一个同名的常函数,这时就会存在函数覆盖:
******illustrate********
#include <iostream.h>
class test
{
public:
void output()
{
cout<<"this is base"<<endl;
}
};
class member
{
public:
void greet()
{
cout<<"this is a member"<<endl;
}
};
class derive:public test
{
private:
member x;//because member have not parameters, so don't need constructor
public:
void output()
{
cout<<"this is a derive"<<endl;
x.greet();
}
};
int main()
{
derive de;
de.output();
de.test::output(); //if want to invoking the father class's function, must append the ::
return 0;
}
****the answer******
this is a derive
this is a member
this is base
now, we modify above programe, append the constructor
成员类和父类构造器的初始化,初始化父类时,使用的是类名,初始化成员类时,使用的是成员名
#include <iostream.h>
class test
{
private:
int x;
public:
test(int y)
{
x=y;
}
void output()
{
cout<<"this is base"<<endl;
}
};
class member
{
private:
float f1;
char ch;
public:
member(float f,char ch1)
{
f1=f;
ch=ch1;
}
void greet()
{
cout<<"this is a member"<<endl;
}
};
class derive:public test
{
private:
member x;//because member have not parameters, so don't need constructor
public:
derive(int x1,float y,char chr):test(x1),x(y,chr) //member class and parent class's initialize
{}
void output()
{
cout<<"this is a derive"<<endl;
x.greet();
}
};
int main()
{
derive de(45,12.32,'h');
de.output();
de.test::output();
return 0;
}
构造和析构的调用顺序
先是父类中的成员类的构造函数先调用,然后才是父类的构造函数,接下来就是子类,调用顺序相同,而析构相反。如果继承了多个类(多重继承),则按它们在定义派生类时的声明顺序有关。
*******illustrate***********
#include <iostream.h>
class member
{
public:
member()
{
cout<<"invoking the parent member constructor"<<endl;
}
~member()
{
cout<<"deconstruct"<<endl;
}
};
class test
{
private:
int x;
member xy;
public:
test(int y)
{
cout<<"parent constructor"<<endl;
x=y;
}
~test()
{
cout<<"the parent destruct"<<endl;
}
void output()
{
cout<<"this is base"<<endl;
}
};
class member1
{
private:
float f1;
char ch;
public:
member1(float f,char ch1)
{
f1=f;
ch=ch1;
}
void greet()
{
cout<<"this is a member"<<endl;
}
};
class derive:public test
{
private:
member1 x;//because member have not parameters, so don't need constructor
public:
derive(int x1,float y,char chr):test(x1),x(y,chr)
{cout<<"invoking the derive constructor"<<endl;}
~derive()
{
cout<<"the derive destruct "<<endl;
}
void output()
{
cout<<"this is a derive"<<endl;
x.greet();
}
};
int main()
{
derive de(45,12.32,'h');
de.output();
de.test::output();
return 0;
}
*********over*********
mapping up-----向上映射
we can use the above programe, define a new object
append the follow contents in main:
test te=derive(25,12.36,'a'); //this is mapping up
te.output();
注意:只有公有继承才能向上映射,private, protected不能向上映射
多重继承的二义性
例如:
class base1
{
void display()
{
cout<<"base1"<<endl;
}
};
class base2
{
void display()
{
cout<<"base2";
}
};
class derive:public base1,public base2
{
void output()
{
cout<<"the derive class"<<endl;
}
};
int main()
{
derive der;
der.display(); //现在这个语句就会出现二义性,不知调用父类的哪一个常函数,加上作用域就可以了
der.base1::display();
der.base2::display();// now, it can run rightly
return 0;
}
访问共同基类成员时的二义性
class base
{
public:
base()
{
cout<<"base constructor"<<endl;
}
void common()
{
cout<<"base"<<endl;
}
};
class base1:public base
{
public:
base1()
{
cout<<"base1.constructor"<<endl;
}
void display()
{
cout<<"base1"<<endl;
}
};
class base2:public base
{
public:
base2()
{
cout<<"base2.constructor"<<endl;
}
void display()
{
cout<<"base2";
}
};
class derive:public base1,public base2
{
public:
void output()
{
cout<<"the derive class"<<endl;
}
};
int main()
{
derive der;
//der.common(); //现在这个就会出现二义性,因为不知是通过哪个父类调用父类的父类
//解决办法,仍然是用作用域来解决。只不过会对父类有两次拷贝
der.base1::common();
return 0;}
******the result******
base constructor
base1.constructor
base constructor
base2.constructor
base
从以上结果可以看出,基类的构造函数被调用了两次。
*******虚基类*************
利用上面的程序,只需在继承自共同基类的派生类声明时显示地标明继承方式为虚拟(virtual)继承,其格式为:
<derived name>:<virtual><inherit mode><base name>
******illustrate**********
class base
{
public:
base()
{
cout<<"base constructor"<<endl;
}
void common()
{
cout<<"base"<<endl;
}
};
class base1:virtual public base
{
public:
base1()
{
cout<<"base1.constructor"<<endl;
}
void display()
{
cout<<"base1"<<endl;
}
};
class base2:virtual public base
{
public:
base2()
{
cout<<"base2.constructor"<<endl;
}
void display()
{
cout<<"base2";
}
};
class derive:public base1,public base2
{
public:
void output()
{
cout<<"the derive class"<<endl;
}
};
int main()
{
derive der;
der.common(); //现在这个就不会出现二义性
//der.base1::common();
return 0;}
the result:
base constructor
base1.constructor
base constructor
base2.constructor
base
从以上结果可以看出,父类的构造函数只调用了一次
虚基类的初始化
在虚拟继承中,必须在最晚派生类的构造函数中显式地调用虚基类的构造函数,其格式如下:
<the last derive class constructor><parameter list><direct base's constructor><member object constructor><virtual base class constructor>{define new append members }
*******illustrate*******
#include <iostream.h>
class base
{
private:
int i;
public:
base(int x)
{
i=x;
cout<<"base constructor"<<endl;
cout<<i<<endl;
}
int geti() const
{
return i;
}
void common()
{
cout<<"base"<<endl;
}
};
class base1:virtual public base
{
int y;
public:
base1(int w,int z):base(w)
{
y=z;
cout<<"base1.constructor"<<endl;
}
void display()
{
cout<<"base1"<<endl;
}
};
class base2:virtual public base
{private:
int aa;
public:
base2(int a, int b):base(b)
{
aa=a;
cout<<"base2.constructor"<<endl;
}
void display()
{
cout<<"base2";
}
int geti() const
{
return aa;
}
};
class derive:public base1,public base2
{
public:
derive(int a1,int a2,int a3,int a4):base1(a1,a2),base2(a3,a4),base(a4){}
//initialize the virtual base class constructor
void output()
{
cout<<"the derive class"<<endl;
}
};
int main()
{
derive der(12,25,34,45);
der.common(); //
//
//der.base1::common();
cout<<der.geti()<<endl;
return 0;}
http://www.baidu.com/s?ie=gb2312&bs=c%2B%2B+%C0%E0&sr=&z=&cl=3&f=8&wd=sun+directory+server&ct=0
ldap学习笔记:http://linliangyi2007.javaeye.com/blog/167125
安装 Sun ONE Directory Server: http://publib.boulder.ibm.com/tividd/td/ITAME/SC32-1362-00/zh_CN/HTML/am51_install78.htm
折腾sunONE directory server: http://www.ningoo.net/html/2007/install_sun_one_directory_server.html
Sun Java System Directory Server Enterprise Edition 6.2:
http://docs.sun.com/app/docs/coll/1224.3?l=zh_TW
ldap_API_C URL:http://www.diybl.com/course/7_databases/database_other/20071019/78240.html
ldap学习笔记:http://linliangyi2007.javaeye.com/blog/167125
安装 Sun ONE Directory Server: http://publib.boulder.ibm.com/tividd/td/ITAME/SC32-1362-00/zh_CN/HTML/am51_install78.htm
折腾sunONE directory server: http://www.ningoo.net/html/2007/install_sun_one_directory_server.html
Sun Java System Directory Server Enterprise Edition 6.2:
http://docs.sun.com/app/docs/coll/1224.3?l=zh_TW
ldap_API_C URL:http://www.diybl.com/course/7_databases/database_other/20071019/78240.html
Linux的问题往往不是集中在技术或软件的可获得性问题,而是一个选择的问题。用户图形界面(GUI)的选择就体现了这一点。在Linux领域可以选择的GUI很多,商业可用的也有10种左右。当我们面临着如何为LiPS论坛选择可以成为标准的GUI时,技术偏好就必须让位于更多的公共性的因素。常常提起的是,作者个人与主要的GUI提供者例如QT(TrollTech),MiniGUI(魏老师),mGUI(移软)都有着相当长的个人和业务关系,所以这个选择就显得更加的“人情化”。如果没有一个科学的和公正的立场,那么结果可想而知。
从标准化角度和行业利益最大化的角度来看,在选择GUI之前我们设立3个原则:
1、自由原则,GUI的技术和授权方式必须能够为其使用者提供的自由度,既能够支持商业版本的应用,又要能够支持开源的应用。所以,LGPL,BSD, Mozilla等的授权方式比起GPL或者私有的授权协议来说更符合这个原则。
2、成熟原则,GUI必须通过极限应用的检验,例如如果应用环境中平均应用的代码行数在10万行的话,那么这个GUI必须通过超过100万行代码的单个应用的检验。通过这种检验我们可以直观地获得GUI在功能的丰富程度和代码的可扩展和鲁棒性。
3、适用原则,GUI必须是能够直接或者通过裁减运行在嵌入式环境中的,其API兼容性不应该因为这种裁减发生重大改变的(理想状况下是不变的)。
在这3个原则的指导下,我们对QT,miniGUI,GTK等GUI进行了对比,对比结果就不一一列举了。结论是,GTK更接近我们的原则,它是LGPL 的,大量的桌面应用都是基于GTK的,在手机中已经有了超过500万部的使用纪录。但是,美中不足的是,GTK的定制和裁减都是厂商的个体行为,没有回馈到开源社区。
所以,我们将工作的重点放在了加强GTK对“适用原则”的符合程度。我们通过与开源社区合作,提供了一个GTK的嵌入式补丁,目的是通过更改公用部分的处理,例如键盘和鼠标输入的替换等,在不改变Widget接口的情况在,达到嵌入场景的适应性。并且,不断的推动相关人士,加强对GTK社区的说复。目前已经取得初步的进展,首先GTK的主要维护者认识到了嵌入式的需求和目前现实的差距,以及相关机构和个人进行嵌入化的努力,同意在今后的版本中考虑嵌入式的需求。这是关键一步,迈向理想的“适用”,即嵌入并兼容。
从标准化角度和行业利益最大化的角度来看,在选择GUI之前我们设立3个原则:
1、自由原则,GUI的技术和授权方式必须能够为其使用者提供的自由度,既能够支持商业版本的应用,又要能够支持开源的应用。所以,LGPL,BSD, Mozilla等的授权方式比起GPL或者私有的授权协议来说更符合这个原则。
2、成熟原则,GUI必须通过极限应用的检验,例如如果应用环境中平均应用的代码行数在10万行的话,那么这个GUI必须通过超过100万行代码的单个应用的检验。通过这种检验我们可以直观地获得GUI在功能的丰富程度和代码的可扩展和鲁棒性。
3、适用原则,GUI必须是能够直接或者通过裁减运行在嵌入式环境中的,其API兼容性不应该因为这种裁减发生重大改变的(理想状况下是不变的)。
在这3个原则的指导下,我们对QT,miniGUI,GTK等GUI进行了对比,对比结果就不一一列举了。结论是,GTK更接近我们的原则,它是LGPL 的,大量的桌面应用都是基于GTK的,在手机中已经有了超过500万部的使用纪录。但是,美中不足的是,GTK的定制和裁减都是厂商的个体行为,没有回馈到开源社区。
所以,我们将工作的重点放在了加强GTK对“适用原则”的符合程度。我们通过与开源社区合作,提供了一个GTK的嵌入式补丁,目的是通过更改公用部分的处理,例如键盘和鼠标输入的替换等,在不改变Widget接口的情况在,达到嵌入场景的适应性。并且,不断的推动相关人士,加强对GTK社区的说复。目前已经取得初步的进展,首先GTK的主要维护者认识到了嵌入式的需求和目前现实的差距,以及相关机构和个人进行嵌入化的努力,同意在今后的版本中考虑嵌入式的需求。这是关键一步,迈向理想的“适用”,即嵌入并兼容。
#include <stdio.h>;
#include <stdlib.h>;
#include <sys/wait.h>;
#include <sys/types.h>;
int main()
{
pid_t status ;
errno = 0 ;
status = system("cp hello.c hello.c.bak") ;
if (status == -1)
printf("system error!") ;
if (WIFEXITED(status)){
printf("cp exit normal![%d]\n", errno) ;
printf("exit staus = [%X]\n", WEXITSTATUS(status)) ;
}else
printf("cp exit illegal![%d]\n", errno) ;
}
[/code]
测试了一把.结果如下
如果hello.c存在,cp也成功将hello.c拷贝到了hello.c.bak则打印
cp exit normal![0]
exit status = [0]
如果hello.c不存在,则打印
cp exit normal![0]
exit status = [1]
我的问题是.
1.在何种情况下会打印cp exit illegal!
2.如果是exit normal,那么exit status的值是否和system调用执行的进程紧密相关(如本例中的cp)
3.如果上个问题的回答是肯定的,那我该如何得到关于cp的各种退出状态.cp的手册页里好象没有相关说明.
老调重弹--问system返回值
第二个问题我测试了一下,回答是肯定的.
exit status等于被调用程序的用exit(n)或者return n
给出的值.
第一个问题还是不知道.
我在被调用程序运行过程中将他kill掉.
程序还是打印exit normal!可是status取到的值明显是不对的.
faint
老调重弹--问system返回值
UP
老调重弹--问system返回值
WIFEXITED(status)
returns true if the child terminated normally, that is, by call-
ing exit() or _exit(), or by returning from main().
老调重弹--问system返回值
楼上的兄弟谢谢了.
我不明白的正是这个问题.
按照上面的描述,我把被调用的进程kill掉.按照我的理解
WIFEXITED(status)不应该返回真才对.
老调重弹--问system返回值
没有人知道吗?
老调重弹--问system返回值
man里面说-->
不管你有没有hello.c文件。你的system都会正常结束,也就都不会返回-1,区别只是cp动作的结束状态不同。
老调重弹--问system返回值
-->
是的,这个我知道,
我现在想知道的是什么情况下
WIFEXITED(status)不会返回真.
我不明白为什么我把被调用的进程中间KILL掉这个宏的值还是真.
但是WEXITSTATUS(status)的值明显不是被调用进程的返回值.
老调重弹--问system返回值
你怎么kill掉的呢?cp之间你kill它?^_^,我也不太明白。
老调重弹--问system返回值
[code]
#include <stdio.h>;
#include <stdlib.h>;
#include <sys/wait.h>;
#include <sys/types.h>;
int main()
{
pid_t status ;
errno = 0 ;
status = system("./hi") ;
if (status == -1)
printf("system error!") ;
if (WIFEXITED(status)){
printf("process exit normal![%d]\n", errno) ;
printf("exit staus = [%X]\n", WEXITSTATUS(status)) ;
}else
printf("process exit illegal![%d]\n", errno) ;
}
[/code]
[code]
int main()
{
printf("HI!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n") ;
sleep(20) ;
return 4 ;
}
[/code]
这样就可以做到在运行中把进程"hi"kill掉了.
如过是正常退出WEXITSTATUS(status)的值是4
如果是KILL掉
WIFEXITED(status)J还是真,但是WEXITSTATUS(status)的值却是86
这个86真让人faint.
#include <stdlib.h>;
#include <sys/wait.h>;
#include <sys/types.h>;
int main()
{
pid_t status ;
errno = 0 ;
status = system("cp hello.c hello.c.bak") ;
if (status == -1)
printf("system error!") ;
if (WIFEXITED(status)){
printf("cp exit normal![%d]\n", errno) ;
printf("exit staus = [%X]\n", WEXITSTATUS(status)) ;
}else
printf("cp exit illegal![%d]\n", errno) ;
}
[/code]
测试了一把.结果如下
如果hello.c存在,cp也成功将hello.c拷贝到了hello.c.bak则打印
cp exit normal![0]
exit status = [0]
如果hello.c不存在,则打印
cp exit normal![0]
exit status = [1]
我的问题是.
1.在何种情况下会打印cp exit illegal!
2.如果是exit normal,那么exit status的值是否和system调用执行的进程紧密相关(如本例中的cp)
3.如果上个问题的回答是肯定的,那我该如何得到关于cp的各种退出状态.cp的手册页里好象没有相关说明.
老调重弹--问system返回值
第二个问题我测试了一下,回答是肯定的.
exit status等于被调用程序的用exit(n)或者return n
给出的值.
第一个问题还是不知道.
我在被调用程序运行过程中将他kill掉.
程序还是打印exit normal!可是status取到的值明显是不对的.
faint
老调重弹--问system返回值
UP
老调重弹--问system返回值
WIFEXITED(status)
returns true if the child terminated normally, that is, by call-
ing exit() or _exit(), or by returning from main().
老调重弹--问system返回值
楼上的兄弟谢谢了.
我不明白的正是这个问题.
按照上面的描述,我把被调用的进程kill掉.按照我的理解
WIFEXITED(status)不应该返回真才对.
老调重弹--问system返回值
没有人知道吗?
老调重弹--问system返回值
man里面说-->
不管你有没有hello.c文件。你的system都会正常结束,也就都不会返回-1,区别只是cp动作的结束状态不同。
老调重弹--问system返回值
-->
是的,这个我知道,
我现在想知道的是什么情况下
WIFEXITED(status)不会返回真.
我不明白为什么我把被调用的进程中间KILL掉这个宏的值还是真.
但是WEXITSTATUS(status)的值明显不是被调用进程的返回值.
老调重弹--问system返回值
你怎么kill掉的呢?cp之间你kill它?^_^,我也不太明白。
老调重弹--问system返回值
[code]
#include <stdio.h>;
#include <stdlib.h>;
#include <sys/wait.h>;
#include <sys/types.h>;
int main()
{
pid_t status ;
errno = 0 ;
status = system("./hi") ;
if (status == -1)
printf("system error!") ;
if (WIFEXITED(status)){
printf("process exit normal![%d]\n", errno) ;
printf("exit staus = [%X]\n", WEXITSTATUS(status)) ;
}else
printf("process exit illegal![%d]\n", errno) ;
}
[/code]
[code]
int main()
{
printf("HI!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n") ;
sleep(20) ;
return 4 ;
}
[/code]
这样就可以做到在运行中把进程"hi"kill掉了.
如过是正常退出WEXITSTATUS(status)的值是4
如果是KILL掉
WIFEXITED(status)J还是真,但是WEXITSTATUS(status)的值却是86
这个86真让人faint.