taocoding


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

PostgreSQL简单封装

发表于 2011-03-01 | 分类于 C++ , 系统编程

工作需要,虽然有libpqxx,但是目前为了刚刚够用,尽量不要引入第三方库。在网上找到简单的封装http://www.touspassagers.com/2010/12/a-postgresql-database-interface-wrapper-in-c/

 

直接贴上代码:

#include <iostream>

#include <stdio.h>

#include <string>

#include <stdlib.h>

#include <libpq-fe.h>

#include <map>

#include <math.h>

#include <string.h>
using namespace std;
typedef map<int,map<string,string> > map_result;
static void
finish_connection(PGconn conn)
{
PQfinish(conn);
}
class Conn
{
public:
// Methods
Conn(char
connstring);
~Conn();
map_result fetch(char SQL);
int insert(char
SQL);
void reset();
private:
// Members
PGconn conn;
const char
conninfo;
PGresult res;
};
Conn::Conn(char
connstring)
{
// Connect to the DB
conninfo = connstring;
conn = PQconnectdb(conninfo);
// See if the connection took:
if (PQstatus(conn) != CONNECTION_OK)
{
fprintf(stderr, “Could not connect to db/n%s”,
PQerrorMessage(conn));
finish_connection(conn);
}
}
Conn::~Conn()
{
finish_connection(conn);
}
void Conn::reset()
{
PQfinish(conn);
conn = PQconnectdb(conninfo);
}
map_result Conn::fetch(char SQL)
{
int row, col;
map_result results;
map<string,string> pairs;
// Check the connection:
if (PQstatus(conn) != CONNECTION_OK)
this->reset();
// Start a transaction:
res = PQexec(conn, “BEGIN”);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, “Failed to BEGIN transaction /n%s”,
PQerrorMessage(conn));
PQclear(res);
finish_connection(conn);
}
// Set up fetch query with a CURSOR:
string FinalSQL = string(“DECLARE myportal CURSOR FOR “) +
string(SQL);
// Declare CURSOR and execute query:
res = PQexec(conn,FinalSQL.c_str());
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, “QUERY FAILED/n%s/n”,
PQerrorMessage(conn));
PQclear(res);
finish_connection(conn);
}
PQclear(res);
// Fetch results:
res = PQexec(conn, “FETCH ALL in myportal”);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
fprintf(stderr, “FETCH ALL failed/n%s/n”,
PQerrorMessage(conn));
PQclear(res);
finish_connection(conn);
}
else
{
row = col = 0;
for (row=0; row<PQntuples(res); row++)
{
for(col=0; col<PQnfields(res); col++)
{
pairs[PQfname(res,col)] = PQgetvalue(res, row, col);
}
results[row] = pairs;
}
}
return results;
}
int Conn::insert(char
sql)
{
// Check the connection:
if (PQstatus(conn) != CONNECTION_OK)
this->reset();
// Start a transaction:
res = PQexec(conn, “START TRANSACTION;”);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, “Failed to BEGIN transaction /n%s/n”,
PQerrorMessage(conn));
PQclear(res);
finish_connection(conn);
}
// Execute Insert:
res = PQexec(conn, sql);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, “Failed to execute INSERT /n%s/n”,
PQerrorMessage(conn));
PQclear(res);
finish_connection(conn);
}
// COMMIT transaction:
res = PQexec(conn, “COMMIT”);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, “Failed to COMMIT transaction/n%s/n”,
PQerrorMessage(conn));
PQclear(res);
finish_connection(conn);
}
return 0;
} 

使用代码:

#include <iostream>

#include <boost/lexical_cast.hpp>

#include “PGConn.hpp”
using namespace std;

int main()
{
map_result res;
Conn postgres = new Conn(“dbname=mydb user=postgres”);
for( int i=0; i<10; ++i )
{
std::string strTemp( “(“ +boost::lexical_cast<std::string>(i) + “,” );
strTemp += boost::lexical_cast<std::string>(i+1) + “,”;
strTemp += boost::lexical_cast<std::string>(i+2) + “);”;
std::string strSql(“INSERT INTO exam_en(language,math,computer) VALUES “ + strTemp );
postgres->insert( (char
)strSql.c_str() );
}
char sql[] = “SELECT * FROM exam_en;”;
res = postgres->fetch(sql);
map_result::iterator it = res.begin();
for( ; it!=res.end(); ++it )
{
std::cout << “ROW:” << it->first << std::endl;
map<string,string>::iterator itField = it->second.begin();
for( ; itField!=it->second.end(); ++itField )
{
std::cout << “Field:” << itField->first << “ Value:” << itField->second << std::endl;
}
}
return 0;
}
 

Hello,Java

发表于 2011-01-01 | 分类于 JAVA

新的挑战,也是新的机遇,工作需要开始学习java了,来个Hello吧:

public class Hello
{
public static void main(String[] args)
{
System.out.println(“Hello,2011”);
}
}
 

循环左移-海豚算法

发表于 2010-08-29 | 分类于 数据结构/算法

题目要求是这样的:

 

/*

设将n (n > 1) 个整数存放到一维数组 R中。设计一个在时间和空间两方面尽可能高效的算法。

将 R 中的序列循环左移 p(0 < p < n)个位置,即将 R 中的数据由 (a0, a1, ……an-1)

变换为(ap, ap-1, …an-1, a0, a1, …, ap-1)。要求:

       (1) 给出算法的基本设计思想。

       (2) 根据设计思想,采用C或C++或JaVa语言描述算法,关键之处给出注释。

       (3) 说明你所设计算法的时间复杂度和空间复杂度。

*/

下面是我的一个低效实现:

#include <iostream>
bool circleLeftMove( int nArr[], int nSize, int nMove )
{
//判断边界条件
if( nSize <= 1 )
{
return false;
}
if( nMove <= 0 || nMove >= nSize )
{
return false;
}
//将需要移动的前nMove个数移动到一个缓存中
int *pTemp = new int[nMove];
for( int i=0; i<nMove; ++i )
{
pTemp[i] = nArr[i];
}
//移动nMove开始的剩余数到0~(nSize - nMove)位置上
int nStart = nMove;
for( int j=0; j<(nSize-nMove); ++j )
{
nArr[j] = nArr[nStart++];
}
//将缓存中的数据放到原始数组后面
nStart = nSize-nMove;
for( int i=0; i<nMove; ++i )
{
nArr[nStart++] = pTemp[i];
}
//释放缓存
delete []pTemp;
return true;
}
void print( int arr[], int nSize )
{
for(int i=0; i<nSize; ++i )
{
std::cout << “Num” << i << “==>” << arr[i] << std::endl;
}
}

int main(int argc, char *argv[])
{
int nArr[]={0,1,2,3,4,5,6};
std::cout << “Before Circle Move:” << std::endl;
print( nArr, sizeof(nArr)/sizeof(nArr[0]) );
int nMove;
std::cout << “Please Input The Move Count:”;
std::cin >> nMove;
std::cout << std::endl;
circleLeftMove( nArr, sizeof(nArr)/sizeof(nArr[0]), nMove );
std::cout << “After Circle Move “ << nMove << std::endl;
print( nArr, sizeof(nArr)/sizeof(nArr[0]) );
return 0;
}

只是稍微测试了下,查看参考答案后发现这个算法叫做海豚算法,下面是其给出的参考实现:

大致思路为:

 

首先把序列{ a0, a1, …, ap, …, an-1 }逆转为{an-1, an-2, …, ap, …,a0 },

再分别逆转{ an-1, an-2, …, ap }和{ ap-1, ap-2, …,a0 },

最后得到{ ap, ap+1, …, an-1, a0, …, ap-1}。

void reverse ( int A[ ], int left, int right )
{
int n = right-left+1;
if ( n <= 1 ) return;
if ( n <= 1 ) return;
for ( int i = 0; i < n/2; i++ )
{
int temp = A[i];
A[i] = A[n-i-1];
A[n-i-1] = temp;
}
}
void sift_Left ( int a[ ], int n, int p )
{
reverse ( a, 0, n-1 );
reverse ( a, 0, n-p-1 );
reverse ( a, n-p, n-1 );
}
 

我实现的那个空间复杂度比较高O(p),参考答案的为O(1),时间上面都是O(n)。

通过比较其他实现,发现自己在算法方面确实需要提高,我完全是按照那种常规思路来实现,没有进行任何优化,这在效率有要求的时候显然就不行了,这里还悟出一点道理,高效算法一般都不是大多数人想到的那种常规方法,即根据要求一步步满足,而应该根据算法输出结果来分析其中的规律进而找到突破点。

 

 

Winsock 重复定义的错误

发表于 2010-08-08 | 分类于 VC

Winsock提示重复定义,

这是一个老问题了,之前也碰到过,最近一个项目中再次遇到,摘抄自MSDN:

The Winsock2.h header file internally includes core elements from the Windows.h header file, so there is not usually an #include line for the Windows.h header file in Winsock applications. If an #include line is needed for the Windows.h header file, this should be preceded with the #define WIN32_LEAN_AND_MEAN macro. For historical reasons, the Windows.h header defaults to including the Winsock.h header file for Windows Sockets 1.1. The declarations in the Winsock.h header file will conflict with the declarations in the Winsock2.h header file required by Windows Sockets 2.0. The WIN32_LEAN_AND_MEAN macro prevents the Winsock.h from being included by the Windows.h header. An example illustrating this is shown below.

 

 


#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
int main() {
return 0;
}
大意就是因为MS由于历史原因,在Windows.h头文件中包含了Winsock.h,导致与Winsock2.h冲突,所以提示重复定义。


我看敏捷

发表于 2010-07-18 | 分类于 软件工程

      现在行业里很多人都在谈论敏捷开发,这是一个热点,象Thoutwork这样的公司也正在企图把敏捷开发模式做为企业的核心竞争力之一,可见敏捷已经超越了传统的软件开发方法的范畴,变成了具有商业要义的业务模式。

 

      什么叫敏捷,其实无论有多少定义,其核心就是一点:快速向客户交付软件产品,快速响应客户的需求变化。为了实现这几个快速,软件公司可以在风险可控的基础上,忽略很多传统开发的流程、规范方面的工作要求,因为这些要求在敏捷者(我们用这个词来称呼那些推崇敏捷开发的人士)看来,其实都是与最终交付的软件产品没有太大的关系,是属于不能直接产生交付收益的无效工作。

 

      从软件业务的本质上来看,我是赞同这种思路的。就像中国武术,在很长时间里被人戏称为“舞术”,不管猴拳、猫拳,花架子一大堆,中看不中用,远不如韩国的跆拳道、日本的柔道那样一招致敌、简单实用,所以有了花拳绣腿的称谓。也正是因为这样,1970年代以后,那个拍功夫片的李小龙创建了截拳道,其实就是一种散打,目的很明确,几招之内,搞定对手。现在看到的李小龙的武打片中,几乎没用漂亮的拳脚,但是往往都是在几声怪叫之后,敌人便趴在地上了。其实做任何事情都一样,为了达到目标,一定有一个最近的路径,一定有一种最简单的方法。我想,敏捷开发的精髓恐怕也在于此。当我们抓住了要向客户交付产品--软件程序这样的本质需求后,就开始要思考那些最简洁的方式和那条最近的路线了。

 

      这一段时间,看了基本关于敏捷的书籍,也在网上浏览了几篇敏捷的文章,访问了几个采用敏捷方法的公司网站,也得到了一些印象。顺便说一下,本人看书从来都是不求甚解的,所以每本书基本上得到的是一些模糊的印象,所以对于本人来讲,很难博闻强识、引经据典。我对于这些敏捷资料的基本印象是,多数人在讨论敏捷时,往往是都从程序开发的角度来完成敏捷,因此,这时的敏捷其实是基于XP的一种开发模式。不过,既然是XP,那么能够完成那个P的Programmer(程序员)就是一个关键因素了。

 

      前几天,我在google上搜索thougtwork,结果发现,很多竟然是关于如何通过这家公司面试的纪录。说句题外话,中国的工程师其实也很可怜,这么多人在网上花费大量的时间交流的仅仅是获得一份工作的经验,把进洋人开的公司、给洋人打工看成是人生的一个里程碑式的成就。先贤说中国知识分子缺乏独立的人格,以前可能是指政治上的,是政治的小妾,而从今天看去,恐怕还要加上商业这一条了,对老板、对洋人的谄媚几乎也成了知识分子这个对象的基本属性之一。从这些面试纪录里可以看到,thoughtwork的面试过程很严格,给的待遇当然也不错,中国的工程师趋之若鹜,最后的录用比例好像是10:1。我感兴趣的则是thouhtwork面试的内容,从那些成功者的经验报告中透露的一些信息来看,多数应该是软件设计技能、程序开发技能方面的东西,说实话,那些考题如果让我去做,估计100%的要死菜菜。我的一个曾经部下参加过他们的面试,结果第一轮都淘汰了。

 

      从我所了解的一些信息,我们有必要需要来讨论怎样进行敏捷。

 

      做软件,本质上也是一种业务,因此,讨论软件的开发方法,最好把出发点放在业务模式来讨论。正象前面说的,敏捷发展到今天,其实也变成了一种业务模式。OK,我们这里就来讨论一下软件业务的问题。现在所有的软件公司几乎都面临一个问题,就是做软件不赚钱,软件的利润实在太薄。这里面的既有市场环境的问题,同时也有软件公司自己的问题。话说回来,中国有成千上万家软件公司,但是到底有几家真正懂得做软件业务的呢。这几年,关于软件业务模式的创意层出不穷,方法也多种多样。有人提倡大客户服务,这样模式下,市场的开拓成本不大,而且比较稳定,但是大客户的预算也经常波动,而且客户的主管胃口也越来越大,以前的许多假设实际上已经不成立。也有人提倡做人力外包,公司就是卖人头,好处是现金流压力小,业务稳定,但是在这种模式下,正是由于公司的收入清晰可见,老板们很少愿意把装在兜里的钱再掏出来做公司的能力建设,所以时间长了,软件公司的服务能力一定是向下衰减,直到有一天客户忍无可忍,另寻新欢。还有人希望从软件工具方面来解决问题,于是就有了各种各样的框架平台,据说这是一颗能够搞定软件业务的“银弹”,于是滋生了几家做平台的软件公司,不幸的是,平台也仅仅是工具,决定项目成败的关键因素肯定不是平台,这些做平台的公司最后免不了还是得去做项目。有了飞机大炮,也未必能够打得赢小米加步枪。

 

      现在出来了敏捷开发,而且已经成为了一种业务模式,那么就敏捷业务模式来讲,我们要深入地进行一些讨论。既然是业务模式,那么与之相关的第一个问题就是,敏捷的支持体系是什么,怎样建立。说到底,这是一种业务。

 

我们来看thoughtwork,它是在XP的思想下来实施敏捷的,所以它需要找的人一定是一些相对比较高档的程序员,既可以写出高质量的代码,同时又能够快速理解客户的业务,并且可以随时因客户需求而变。

 

但是,如果我们回到现实中间,我们会发现这种模式至少在国内是极度危险的。

 

首先,国内的市场似乎没用这么大的利润空间给一家软件公司去养这么多的高档程序员,即使这些程序员能够快速交付他们所承诺的任务(不过就我个人来看,我对国内市场上的程序员的这方面的能力的认识还是有所保留的)。只有一种可能性,象thoughtwork这样的公司可以持续地、从海外接受利润较好的软件订单,这样才可能管得住这群高档程序员的吃喝拉撒。

 

其次,国内市场上实际是缺乏一个能够适应XP、同时又相对比较稳定的程序员群体。在这里,我们简单地给国内的程序员群体来做一个分类,大概有三种类型:

 

第一类就是那些优秀、勤奋同时又懂得把握机遇的群体,在几年艰苦的项目生活之后,多数都进入了各个软件公司的庙堂,成为了公司的中高级管理者,或者公司的基干技术人员,例如咨询师、架构师等等,他们在一定时间后,一般不再承担一线客户项目的开发任务。

第二类则是那些资质较弱,或者有一些惰性的程序员,在软件公司干了10年左右,不上不下,高不成、低不就。这群人多数是缺乏激情、缺乏创新的老程序员,靠跳槽加薪,靠在网上晒工资条宣泄自己的优越感。当然,这群人并非一无是处,凭良心讲,在开发经验上和程序质量上,他们的工作绩效还是要比刚刚入行的程序员强了许多,到底多吃了好几年的IT饭。但是不幸的是,他们的成本也是年轻程序员的若干倍,对于公司来讲,这群人的投入产出是不成比例的。在国内软件公司中,我个人感到,最没有价值的就是工作了7、8年,每月拿8000左右的高级程序员。这群人向上,既不能带队伍做管理,独立承担责任;又不能做系统分析设计,在项目组中仅仅是一个优秀的技工而已;向下,当承担一些具体工作时,往往又摆老资格,讲条件,纪律涣散,动辄在项目中就要跳槽,置团队整体利益于不顾,是实实在在的鸡肋。这群人,我们可以称之为打工油子。

第三类则是那些工作时间不长,涉世不深,还保留了一些朝气和单纯的年轻程序员群体,他们可能能力、经验不足,但是多数追求上进,至少还有些热情,当然成本也相对较低,这些可能是现在软件公司应该重视的资源。

做软件开发要培训团队,就我的认识来讲,培训那些初出校门的年轻人其实是建立基干团队的最佳途径。当初戚继光训练戚家军时,最反感的就是老兵油子,宁可从头招募农民、矿工等良家子弟,也不要那些颇有些实战经验的老兵。

 

一般而言,在中国,学而优则仕,同样也是技而优则仕,程序员的事业发展肯定不能是在程序员岗位上,发展几年,如果有一些业绩了,肯定会转行,或者做管理,或者做咨询,或者干脆去做销售,优秀人才的人生追求在客观上会不断地削弱优秀的资深程序员的群体。这是国民性造成的,也是行业待遇体制的原因。虽然很多欧美公司都在宣扬一种老程序员的文化,但是程序员毕竟不是科学家,科学家越老越值钱,而程序员则是和女人相似,越老越没有人要,老的科学家是国宝,老的女人这里就不说了,而老的程序员几乎与老的女人有的一拼。这就是中国的文化环境。少数几个欧美公司的这种倡议,最终只能让那些老程序员做冤大头。

 

所以,在国内,程序员团队的组建只能依托于年轻的群体,要能够形成年轻程序员源源不断的资源梯队。到了30岁左右,程序员就应该主动寻找发展的机遇,过了30岁还在项目组做程序员的人,就要考虑自己的职业生涯的风险了。一个人,在30岁或者35岁的时候,还在抱着简历求一份基层的职位,本身就是一件很悲哀的事情。至少我在筛选简历的时候,对30岁以上的程序员是有所保留的,尤其那些在简历中动辄要价的人,呵呵,他们可能没有想到,在我这里,超过一定薪酬的人是必须找猎头或者熟人推荐的,行业中几乎没有公司会在公共渠道获得的简历中寻找中高级的人员的。

 

鉴于此,回到我们要讨论的专题,我们要实现敏捷。按照道理来讲,敏捷最好的基础是程序员,而程序员资源应该是一些30岁左右的人群。但是在国内这个人群又恰恰是不怎么优秀或者是打工油子的那一群人。呜呼,在这样的基础上进行XP,实施敏捷,谬矣。所以,现在很多公司的敏捷模式实际上是要检讨的。

 

目前,我们能够利用的只能是一些没有太多经验,但是还有一些朝气的人,这是我们真正可以利用的资源,我们要在他们的基础上开始敏捷。OK,相信很多公司都在探索,我们也在探索。

 

既然如此,那就让优秀的人发挥作用吧。

 

每个软件项目,基本的规律是必须有一个象毛主席那样的指路人,这是先知,一眼可以看到20年后,把项目的需求、设计、架构、程序、团队、计划和后期的扩展,全部了然于胸,胸有成竹。如果这种前提存在,我相信,至少项目很少会走弯路了,而敏捷也不是梦了。另外,Thoughtwork的面试也不会那么辛苦了。

 

事实上,XP走的是群众路线,靠程序员的能力来应对客户的需求,调整软件产品的功能,交付合格的产品。但是,但是就像上面讲的,在国内的环境下,这种群众群体是不存在的。而另一种方式是先知路线,靠的是毛主席式的指路明灯,洞察一切,给整个团队做导师,引导大家在正确的时间,用正确的方法,做正确的事情。这种模式可以依托目前国内的群众环境来完成。只要路线对了头,路线一旦掌握群众,群众就可以创造历史了。

 

这种先知模式产生的敏捷开发方法,其根本是对方案咨询能力的考验。其实,在一个团体里,当优秀的程序员转变成为管理者或者中高端的技术领导者,一定会面临一个问题,就是他们的知识如何在更高的层次上进行放大,转换成为更大的商业价值。而敏捷模式提供了一根杠杆,让优秀程序员沉淀的知识,通过方案能力来撬动巨大的商业回报。

 

这是一种业务模式,群众可以在先知的指导下迅速接近软件的目标,交付符合客户需求的产品。一个软件公司必须有几个先知,否则几十个甚至数百人的团队,茫茫然地摸索,能够开发出高质量的产品,才是奇怪呢。

 

虽然书本上有很多软件方法,指导我们分析、设计、开发产品,但是这些方法在经验目前显得多么地苍白,现实实在是太复杂了。也许真的是一些有灵气、有天分的人,才能在比较短的时间里领悟这些方法,才能与现实世界融会贯通,才能开发出合乎客户需求的软件产品。


一次编程实践

发表于 2010-07-11 | 分类于 软件工程

      某天上午,一同事突然过来对我说,走咱们去搞一次敏捷开发,当时让我稍感困惑,我以为只是像平常一样让我去帮忙看个小问题,由于他对MFC不太熟悉,然来是让我配合一起开发一个小工具,呵呵,看来MFC做小工具还是蛮受欢迎的嘛!

      刚好半年没碰过这东西了,这次正好实践一下敏捷开发,哈哈,山寨版的,他像我描述下了大致需要做个什么东西,然后在纸上画了下界面,由于需求很简单,界面也不负责,我直接拖控件开工了,我们一边讨论一边写代码,这样很快就有一个跑起来的大致框架了,在我一步一步编写讲解以及他自己的MFC基础上,他很快就可以自己上手了,开始我还将一些出数据的包装给弄了个class,后来在他自己写的过程中,发现没必要,我们又稍微重构了下,后来基本上就他自己完成了,第二天上午就完工了,期间我们也交流了几次,不管怎样,这也算的上一次结对编程吧,第一次体验,还不错。

链表练习

发表于 2010-07-04 | 分类于 数据结构/算法

一个简单实用的链表,有时间再完善下其他功能:

#ifndef LINKLIST_H
#define LINKLIST_H

template <typename T>
struct SLink
{
    T m_tData;
    SLink* m_pNetx;
};

template <typename T>
class CLinkList
{
    template <typename R>
    friend std::ostream& operator<< ( std::ostream& os, const CLinkList<R>& list );
public:
    CLinkList()
    {
        m_pHead = new SLink<T>();
        m_pHead->m_tData = T();
        m_pHead->m_pNetx = NULL;
    }
    virtual ~CLinkList()
    {
        SLink<T>* pLink = m_pHead;
        while( pLink )
        {
            SLink<T>* pTempLink = pLink->m_pNetx;
            delete pLink, pLink = NULL;
            pLink = pTempLink;
        }
    }
    //先插入的数据在链表后面
    bool addLink( const T& val )
    {
        SLink<T>* pNewLink = new SLink<T>();
        if( !pNewLink )
        {
            return false;
        }
        pNewLink->m_tData = val;
        pNewLink->m_pNetx = m_pHead->m_pNetx;

        m_pHead->m_pNetx = pNewLink;

        return true;
    }
    //依次将每一个节点插入到head后面
    void reverse()
    {
        SLink<T>* pLink = m_pHead->m_pNetx;
        SLink<T>* pTempLink = NULL;
        //置head的next为空,
        m_pHead->m_pNetx = NULL;
        while( pLink )
        {
            //记录下一个节点
            pTempLink = pLink->m_pNetx;

            //当前节点插入头节点之后,修改其next为之前的头结点的next
            pLink->m_pNetx = m_pHead->m_pNetx;
            m_pHead->m_pNetx = pLink;

            pLink = pTempLink;
        }
    }
protected:
private:
    SLink<T>* m_pHead;
};

template <typename R>
std::ostream& operator<< ( std::ostream& os, const CLinkList<R>& list )
{
    SLink<R>* pLink = list.m_pHead->m_pNetx;
    while( pLink )
    {
        os << pLink << "==>" << pLink->m_tData << std::endl;
        pLink = pLink->m_pNetx;
    }
    return os;
}
#endif // LINKLIST_H

VS使用技巧

发表于 2010-05-21 | 分类于 VC

       各位搞开发的调试代码想必是少不了的,很多情况下都是为了查看当前内存变量,自从用VS2008后,发现其调试功能相对于之前使用的VS98那可是加强不少,个人体会最深的是对于STL调试时很容易看到其内部结构。

       再说说调试中遇到的问题,

1:有时我们定义了一个包含多个嵌套结构的类或者是很长的继承链,当需要查看最底层的某个属性时往往在监视窗口中点’+’’-‘号半天,这样严重影响了效率和情绪(尤其是催得紧时),举个例子下面为了查看某个ACE_INET_Addr 对象内部的实际IP地址:

ACE地址

点了半天加号才找到目的,有时点错了还得狂点减号,+_+。

这里贴上一个定制调试器直接展开预设结构的方法:

首先在找到VS的“…Common7/Packages/Debugger/autoexp.dat”文件

添加以下到[Visualizer]段,

; ACE

ACE_INET_Addr {

  preview  (

             #(

               “ip=”,

                 [(unsigned short)$e.inet_addr_.in4_.sin_addr.S_un.S_un_b.s_b1],

                 “.”,

                 [(unsigned short)$e.inet_addr_.in4_.sin_addr.S_un.S_un_b.s_b2],

                 “.”,

                 [(unsigned short)$e.inet_addr_.in4_.sin_addr.S_un.S_un_b.s_b3],

                 “.”,

                 [(unsigned short)$e.inet_addr_.in4_.sin_addr.S_un.S_un_b.s_b4],

                 “ port=”,

                 [(unsigned short)( ($e.inet_addr_.in4_.sin_port >> 8) + (($e.inet_addr_.in4_.sin_port & 0x00ff) << 8 ) ) ]

              )

            )

}

可以显示ACE_INET_Addr为127.0.0.1:1234格式。

这样以后就方便多了,尤其是经常碰到这样的结构时。

2:我们一般为了进入函数内部经常需要按F11,这对于我们学习别人的代码很有帮助,但是当你只是为了跟到某个函数内部,而这个函数的参数里面又有一些其他构造或者调用代码时,一般都是先进入后者,比如说有下面一段代码:

void test( std::string strTest, boost::share_ptr spTest);

当你调试到调用test时如果直接按F11会首先进到std::string构造函数,接着再按F11会进入boost::share_ptr构造函数,你得再次按F11才会进入test,烦了吧,O(∩_∩)O哈哈~,这时我们可以这样弄:

在HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/VisualStudio/9.0/NativeDE/StepOver下添加字符串类型的键值:

1) 键名stl,键值std/:/:.=NoStepInto

2) 键名boost, 键值boost/:/:.
=NoStepInto

值为正则表达式,/scope表示作用域,/funct表示函数,/oper表示操作符

至此你只需一次F11即可进入test了。

 

以上技巧来源于一位牛X的同事,为了方便以后查询,也为遇到同样问题的人提供方便,特留个记号。

 

写到这里突然想到最近一直在琢磨OO,这里之所以叫技巧,是因为当你知道这个东西后你可以按照同样的方法进行扩展,而不需要太多的学习,而思想却不是这样,你设计并实现某个类,但是并代表不需要学习其他类的设计了,设计真的需要经验,当然也需要灵感,毕竟是设计不是实现。

试用期个人总结

发表于 2010-04-17 | 分类于 生活轨迹

      新的工作,新的试用期,4月初试用期结束了,项目经理倒是记得比较清楚,不用我提就主动给经理说了,更让我意外的是基本工资竟然给多了一点,而且是发的转正后的工资,加之之前每个月都貌似多发了一点点中餐补助,看来今年财运不错呀,希望能继续保持。

      新的环境让接触了不少新东西,也让我再次体会到沟通是很重要的,技术上面没有太多的提升,但是对于大型软件开发的模型有一个初步的认识了,下面主要对这段时间的一点总结:

      开始一个月基本上都是看代码,主要是基础模块部分,大致有Utility模块,分布式接口模块,脚本支持模块,测试支持模块,以及对于大型软件开发比较重要的包-服务模块。由于都是C++写的,因此看着还不是很累,当然第一次看只能大致了解其使用方法,模块化开发感觉很像模板化开发,呵呵。因为开始是打算让我做客户端的,后面看了下Client部分,主要是编译了两个客户端,由于是用Qt做UI,因此也把Qt稍微看了下,接着又把Server看了下,才对整个系统有了一个大体上的了解,因为是平台型的项目,还包括一些硬件设施等。

      年前基本上就是看代码了,听先来的同事说,公司一般在年前那段时间都很闲,呵呵正好让我可以休息下,哈哈。由于后来是确认让我做Server端,因此年后一段时间都是看Server代码了,这里的Server其实通信方面的东西基本上都被分布式接口给屏蔽了,而视频传输又是用的多播,因此Server端主要就是进行管理以及视频调度。我的第一个任务是将别名调度映射到多播调度,算比较easy了,就是内存和数据库的一点操作而已,也正是这个任务让我接下来的任务都和别名调度杠上了,接着主要做了个矩阵的别名调度(这里的矩阵是视频监控领域里面的一个硬件设备),这个任务让对业务的不熟悉暴露得很大,哎其实公司应该对这方面进行培训下的,毕竟开发过程中业务需求是导向嘛,这也导致同事到客户那边测试时出现了问题,郁闷,还好第二次测试顺利通过。

      现在又给整了个新的功能,也是别名方面的调度,但是新增了一个盘以及几个逻辑上的通道,需求没定下来,上面就给我说,导致接口又要修改了,这个就牵涉改动多了,我给Client的接口要改,嵌入式给我的接口要改,这仅是接口了,实现那就不用说了。

      这里还有一点就是由于我们的项目相当庞大,而且N多模板,导致编译时间巨长,听之前的说编一个项目得20多分钟,幸好我来之前已经采用分布式编译,时间大大缩短。

      就这么多了,由于今年比较特殊,也没多少时间放在兴趣上面了,希望一切都好。

大环境

发表于 2010-04-12 | 分类于 生活轨迹

      刚刚看到说Java之父离开Oracle,下面的介绍那叫牛X啊:

James Gosling (1955.5.19-)加拿大出生的程序员,美国工程院院士。以“Java 技术之父”而闻名于世。他是Java 技术的创始人,亲手设计了Java语言,并开发了Java编译器和Java虚拟机,使Java成为了世界上最流行的开发语言。

 

      他自己还说希望2030年的时候仍在写代码,真的觉得那些国家的IT氛围挺好的,就像那些踢球的说欧洲的足球环境一样,也不是在这抱怨啥,纯属一点心里话。毕竟我要是牛X也可以去国外做coder嘛,大家可以想象如果你周围有40岁的人还在代码一线,估计是会被人给BS了,这个我没有做啥考究,毕竟也“涉世不深”,就拿都是coder吧,如果你做界面,估计也会有人会瞧不起你,呵呵,国情,习惯也就好了,或者就当阿Q。

 

1…678…16

billowqiu

157 日志
33 分类
10 标签
GitHub E-Mail
© 2020 billowqiu
由 Hexo 强力驱动
|
主题 — NexT.Pisces v5.1.3