posts - 36, comments - 30, trackbacks - 0, articles - 0

     摘要: //      FastDelegate.h // Efficient delegates in C++ that generate only two lines of asm code!//  Documentation is found at http://www.codeproject.com/cpp/FastD...  阅读全文

posted @ 2008-05-30 11:41 vcommon 阅读(722) | 评论 (0)编辑 收藏

CC="gcc -g -O1" ./configure

posted @ 2008-04-25 17:37 vcommon 阅读(289) | 评论 (0)编辑 收藏

change file format of configure.in from dos to unix, then run autoreconf -vif again

posted @ 2008-04-25 16:29 vcommon 阅读(968) | 评论 (1)编辑 收藏

便利的开发工具-log4cpp快速使用指南

developerWorks
文档选项
将此页作为电子邮件发送

将此页作为电子邮件发送

未显示需要 JavaScript 的文档选项


级别: 初级

李群 (liqun@nsfocus.com)绿盟科技

2003 年 9 月 01 日

log4cpp是个基于LGPL的开源项目,是基于优秀的日志处理跟踪项目Java语言的log4j移植过来的。log4j介绍的文档很多,在java领域使用的也比较广泛,而这个功能强大的库对国内的C++语言开发人员却使用的不多。这里从开发人员使用的角度介绍这个库,使开发人员用最少的代价尽快掌握这种技术。下面先简单介绍一下这个项目的优点(也是log4j的优点),然后分原理,手动使用步骤,配置文件驱动方式使用步骤,其他考虑等方面进行讨论。以下讨论基于log4cpp0.3.4b。

0. 优点

  • 提供应用程序运行上下文,方便跟踪调试;
  • 可扩展的、多种方式记录日志,包括命令行、文件、回卷文件、内存、syslog服务器、Win事件日志等;
  • 可以动态控制日志记录级别,在效率和功能中进行调整;
  • 所有配置可以通过配置文件进行动态调整;
  • 多语言支持,包括Java(log4j),C++(log4cpp、log4cplus),C(log4c),python(log4p)等;




回页首


1. 原理

log4cpp有3个主要的组件:categories(类别)、appenders(附加目的地)、和 layouts(布局)。(为了方便大家理解,文中尽量使用英文原词)

layout类控制输出日志消息的显示样式(看起来像什么)。log4cpp当前提供以下layout格式:

log4cpp::BasicLayout 	   // 以“时间戳 优先级(priority,下文介绍)
                        // 类别(category,下文介绍)
                        // NDC标签(nested diagnostic contexts 下文介绍): 日志信息”。
                        // 如:1056638652 INFO main : This is some info
                        log4cpp::PatternLayout 	// 让用户根据类似于 C 语言 printf 函数的转换模式来指定输出格式。格式定义见代码附带文档。
                        log4cpp::SimpleLayout 	// 以“优先级(priority) - 日志信息”格式显示。
                        

appender类用来输出日志(被layout格式化后的)到一些设备上。比如文件、syslog服务、某个socket等。可以定义自己的appender类输出日志信息到别的设备上,比如应用自身的日子处理进程、数据库等。appender和layout的关系是layout附在appender上,appender类调用layout处理完日志消息后,记录到某个设备上。log4cpp当前提供以下appender:

log4cpp::IdsaAppender 			// 发送到IDS或者logger, 详细见 http://jade.cs.uct.ac.za/idsa/
                        log4cpp::FileAppender 			// 输出到文件
                        log4cpp::RollingFileAppender 	// 输出到回卷文件,即当文件到达某个大小后回卷
                        log4cpp::OstreamAppender 		// 输出到一个ostream类
                        log4cpp::RemoteSyslogAppender 	// 输出到远程syslog服务器
                        log4cpp::StringQueueAppender 	// 内存队列
                        log4cpp::SyslogAppender 		// 本地syslog
                        log4cpp::Win32DebugAppender 	// 发送到缺省系统调试器
                        log4cpp::NTEventLogAppender 	// 发送到win 事件日志
                        

category 类真正完成记录日志功能,两个主要组成部分是appenders和priority(优先级)。优先级控制哪类日志信息可以被这个category记录,当前优先级分为:NOTSET, DEBUG, INFO, NOTICE, WARN, ERROR, CRIT, ALERT 或 FATAL/EMERG 。每个日志信息有个优先级,每个category有个优先级,当消息的优先级大于等于category的优先级时,这个消息才会被category记录,否则被忽略。优先级的关系如下。category类和appender的关系是,多个appender附在category上,这样一个日志消息可以同时输出到多个设备上。

NOTSET < DEBUG < INFO < NOTICE < WARN < ERROR < CRIT < ALERT < FATAL = EMERG

category被组织成一个树,子category创建时优先级缺省NOTSET,category缺省会继承父category的appender。而如果不希望这种appender的继承关系,log4cpp允许使用additivity 标签,为false时新的appender取代category的appender列表。

为了更好的理解上面的概念下面以手动使用方式举例。





回页首


2. 手动使用步骤

手动使用log4cpp的基本步骤如下:

  1. 实例化一个layout 对象;
  2. 初始化一个appender 对象;
  3. 把layout对象附着在appender对象上;
  4. 调用log4cpp::Category::getInstance("name"). 实例化一个category对象;
  5. 把appender对象附到category上(根据additivity的值取代其他appender或者附加在其他appender后)。
  6. 设置category的优先级;
// FileName: test_log4cpp1.cpp
                        // Test log4cpp by manual operation.
                        // Announce: use as your own risk.
                        // Compile : g++ -otest1 -llog4cpp test_log4cpp1.cpp
                        // Run     : ./test1
                        // Tested  : RedHat 7.2 log4cpp0.3.4b
                        // Author  : liqun (liqun@nsfocus.com)
                        // Data    : 2003-6-27
                        #include	"log4cpp/Category.hh"
                        #include	"log4cpp/FileAppender.hh"
                        #include	"log4cpp/BasicLayout.hh"
                        int main(int argc, char* argv[])
                        {
                        // 1实例化一个layout 对象
                        log4cpp::Layout* layout =
                        new log4cpp::BasicLayout();
                        // 2. 初始化一个appender 对象
                        log4cpp::Appender* appender = new
                        log4cpp::FileAppender("FileAppender",
                        "./test_log4cpp1.log");
                        // 3. 把layout对象附着在appender对象上
                        appender->setLayout(layout);
                        // 4. 实例化一个category对象
                        log4cpp::Category& warn_log =
                        log4cpp::Category::getInstance("mywarn");
                        // 5. 设置additivity为false,替换已有的appender
                        warn_log.setAdditivity(false);
                        // 5. 把appender对象附到category上
                        warn_log.setAppender(appender);
                        // 6. 设置category的优先级,低于此优先级的日志不被记录
                        warn_log.setPriority(log4cpp::Priority::WARN);
                        // 记录一些日志
                        warn_log.info("Program info which cannot be wirten");
                        warn_log.debug("This debug message will fail to write");
                        warn_log.alert("Alert info");
                        // 其他记录日志方式
                        warn_log.log(log4cpp::Priority::WARN, "This will be a logged warning");
                        log4cpp::Priority::PriorityLevel priority;
                        bool this_is_critical = true;
                        if(this_is_critical)
                        priority = log4cpp::Priority::CRIT;
                        else
                        priority = log4cpp::Priority::DEBUG;
                        warn_log.log(priority,"Importance depends on context");
                        warn_log.critStream() << "This will show up << as "
                        << 1 << " critical message"
                        << log4cpp::CategoryStream::ENDLINE;
                        // clean up and flush all appenders
                        log4cpp::Category::shutdown();
                        return 0;
                        }
                        





回页首


3. 配置文件驱动方式使用步骤

另一个非常优秀的特征就是通过读取配置文件,确定category、appender、layout等对象。也是我们非常推荐的使用方式,可以灵活地通过配置文件定义所有地对象及其属性,不用重新编码,动态更改日志记录的策略。

Log4cpp主要提供了 log4cpp::PropertyConfigurator 和log4cpp::SimpleConfigurator两种机制(文件格式),但 log4cpp::SimpleConfigurator将来不再支持了,而且格式非常简单,这里就不多说明,自己看源码吧。

配置文件的格式和log4j的配置文件一样,是标准的java属性文件格式。下面是附带的例子配置文件:

# a simple test config
                        #定义了3个category sub1, sub2, sub1.sub2
                        log4j.rootCategory=DEBUG, rootAppender
                        log4j.category.sub1=,A1
                        log4j.category.sub2=INFO
                        log4j.category.sub1.sub2=ERROR, A2
                        # 设置sub1.sub2 的additivity属性
                        log4j.additivity.sub1.sub2=false
                        #定义rootAppender类型和layout属性
                        log4j.appender.rootAppender=org.apache.log4j.ConsoleAppender
                        log4j.appender.rootAppender.layout=org.apache.log4j.BasicLayout
                        #定义A1的属性
                        log4j.appender.A1=org.apache.log4j.FileAppender
                        log4j.appender.A1.fileName=A1.log
                        log4j.appender.A1.layout=org.apache.log4j.SimpleLayout
                        #定义A2的属性
                        log4j.appender.A2=org.apache.log4j.ConsoleAppender
                        log4j.appender.A2.layout=org.apache.log4j.PatternLayout
                        log4j.appender.A2.layout.ConversionPattern=The message '%m' at time %d%n
                        

配置文件语法如下,不是很规范,结合上面的例子,应该可以看懂。

		log4j / log4cpp . [category / appender].[category or appender 's name].[category or appender 's property]
                        = [Appender / Layout / property's value / Priority, appender name1 [appender name2 ...]]
                        [appender]
                        {ConsoleAppender}
                        {FileAppender}	// 当appender的类型是FileAppender时,可以定义它下面的属性。
                        [fileName]	string	foobar	// 格式是:属性名 值的类型 缺省值
                        [append]	bool	true
                        {RollingFileAppender}
                        [fileName] 	string	foobar
                        [maxFileSize]	num	10*1024*1024
                        [maxBackupIndex]	num	1
                        [append]	bool	true
                        {SyslogAppender}
                        [syslogName]	string	syslog
                        [syslogHost]	string	localhost
                        [facility]	num	-1	// * 8 to get LOG_KERN, etc. compatible values.
                        [portNumber]	num	-1
                        {IdsaAppender}
                        [idsaName]	string	foobar
                        {Win32DebugAppender}
                        {NTEventLogAppender}
                        [source]	string	foobar
                        [threshold]	string ""	// 全部
                        // 如果此类型appender需要layout,必须定义此appender的下面属性
                        [layout]
                        {BasicLayout}
                        {SimpleLayout}
                        {PatternLayout}		// 当layout的值是BasicLayout时,需要定义下面的属性。
                        [ConversionPattern]
                        [rootCategory]
                        [additivity]
                        [category name]	bool	true
                        

基本使用步骤是:

  1. 读取解析配置文件;
  2. 实例化category对象;
  3. 正常使用这些category对象进行日志处理;

下面是个简单的使用代码,使用起来是非常方便的:

// FileName: test_log4cpp2.cpp
                        // Test log4cpp by config file.
                        // Announce: use as your own risk.
                        // Compile : g++ -llog4cpp test_log4cpp2.cpp
                        // Run     : ./a.out
                        // Tested  : RedHat 7.2 log4cpp0.3.4b
                        // Author  : liqun (liqun@nsfocus.com)
                        // Data    : 2003-6-27
                        #include "log4cpp/Category.hh"
                        #include "log4cpp/PropertyConfigurator.hh"
                        int main(int argc, char* argv[])
                        {
                        // 1 读取解析配置文件
                        // 读取出错, 完全可以忽略,可以定义一个缺省策略或者使用系统缺省策略
                        // BasicLayout输出所有优先级日志到ConsoleAppender
                        try {
                        log4cpp::PropertyConfigurator::configure("./log4cpp.conf");
                        } catch(log4cpp::ConfigureFailure& f) {
                        std::cout << "Configure Problem " << f.what() << std::endl;
                        return -1;
                        }
                        // 2 实例化category对象
                        // 这些对象即使配置文件没有定义也可以使用,不过其属性继承其父category
                        // 通常使用引用可能不太方便,可以使用指针,以后做指针使用
                        // log4cpp::Category* root = &log4cpp::Category::getRoot();
                        log4cpp::Category& root = log4cpp::Category::getRoot();
                        log4cpp::Category& sub1 =
                        log4cpp::Category::getInstance(std::string("sub1"));
                        log4cpp::Category& sub3 =
                        log4cpp::Category::getInstance(std::string("sub1.sub2"));
                        // 3 正常使用这些category对象进行日志处理。
                        // sub1 has appender A1 and rootappender.
                        sub1.info("This is some info");
                        sub1.alert("A warning");
                        // sub3 only have A2 appender.
                        sub3.debug("This debug message will fail to write");
                        sub3.alert("All hands abandon ship");
                        sub3.critStream() << "This will show up << as " << 1 << " critical message"
                        << log4cpp::CategoryStream::ENDLINE;
                        sub3 << log4cpp::Priority::ERROR
                        << "And this will be an error"
                        << log4cpp::CategoryStream::ENDLINE;
                        sub3.log(log4cpp::Priority::WARN, "This will be a logged warning");
                        return 0;
                        }
                        





回页首


4. 相关考虑

性能问题,可能是很多想使用log4cpp的程序员关心的问题。在参考资料2中有一段描述。结论就是log4j以及log4cpp是以性能为首要目标的;如果关闭日志记录的话,对性能影响可以忽略;打开日志记录,主要消耗是在记录动作,而不是库的管理过程;所以你尽可放心的使用。实在要深究性能的话。可以从下面方面提高:

输出的日志消息不要使用复杂的转换或者处理,比如: sub1.debug(string("Current num is") + i + GetCurStat()); 这种情况即使不进行日志处理,括号中的语句还是会执行。变通方法是:

if(sub1.isDebugEnabled())
                        {
                        sub1.debug(string("Current num is") + i + GetCurStat());
                        }
                        

安全性问题对于商业软件开发可能也是问题。可能不希望别人通过修改配置文件获取程序的调试等程序内部运行情况的日志信息。比较稳妥的方案或者是加密配置文件,运行中解密,输出到临时文件后读取;或者在发行版本里读取配置文件后,强行把低于某个优先级的category设到比较高的优先级。

多线程安全性问题。当前log4cpp还没有宣称自己是多线程安全的,不过其代码中大多数可能冲突的地方都增加了线程互斥控制,对多线程环境应该问题不大。但为了加入这个特性,linux下编译log4cpp时,configure请加入--with-pthreads 或者--with-omnithreads选项。Win版本已经加入对MS线程的支持。

posted @ 2008-04-21 17:25 vcommon 阅读(797) | 评论 (0)编辑 收藏

VTD xml以下一代xml的处理著称,xsimpleware是一个java开源的VTD xml parser,已经移植到C/c#上.

使用小记:
VTDGen *vg = NULL;
 VTDNav *vn = NULL;
 UCSChar *string = NULL;
  vg = createVTDGen();
  if (parseFile(vg,TRUE,"G:\\ximpleware_2.4_c\\ximpleware_2.4_c\\vtd-xml\\examples0\\debug\\input.xml")){
   vn = getNav(vg);
   if (toElementNS(vn,FIRST_CHILD,L"someURL",L"b")){
    int i = getText(vn);
    if (i!=-1){
     string = toString(vn,i);
     wprintf(L"the text node value is %d ==> %s \n",i,string);
     free(string);
    }
   }
   free(vn->XMLDoc);
  } else {
   free(vg->XMLDoc);
  }

VTD的效率在DOM和SAX比较上应该是最高的,我认为效率高不等于该用。
VTD抽象出来的数据使xml的处理由简单变为复杂,违背了xml的初衷。
应该在程序设计上把xml简化或者分为多个xml的方法,分阶段和时间处理,合理释放不使用的xml ,始程序达到最优,
这要比为了效率而将xml处理变成晦涩的处理 更加有意义。

xsimpleware并不晦涩,相反在某方面来说还是相当好用的,提供了XPath的查找,相当的方便。
xsimpleware的优势在于对大xml文件处理的效率和对xml的复制,粘贴等操作,对parser和处理xml语义方面要比 DOM或者SAX弱的多。

posted @ 2008-04-21 16:46 vcommon 阅读(1467) | 评论 (1)编辑 收藏

1:Expat xml parser(摘选),大概诞生于1999年,经典code
可以在許多平台使用,Expat是一個stream導向的parser library。
expat也有不少wrapper library,譬如Python、Perl、Tcl、C++....等等。
Expat使用callback function來處理狀態改變的動作,所以當你需要對某些tag做處理的時候你必須要設定相關的處理函式,這裡我們只對最簡單的型式做處理,因此我只設定start tag、end tag與default handler:
::XML_SetUserData(parser, this);
::XML_SetElementHandler(parser, expatStart, expatEnd);
::XML_SetDefaultHandler(parser, expatHandler);

http://www.codeproject.com/KB/XML/expatimpl.aspx c++ wrapper for Expat xml parser

2:XercesParser
Xerces
parser支持的方式很多,但是不易用。
CEGUI:#define CEGUI_DEFAULT_XMLPARSER XercesParser
add define CEGUI_WITH_XERCES

        XercesHandler xercesHandler(handler);

        // create parser
        SAX2XMLReader* reader = createReader(xercesHandler);

        try
        {
            // set up schema
            initialiseSchema(reader, schemaName, filename, resourceGroup);
            // do parse
            doParse(reader, filename, resourceGroup);
        }
3:微软的xml2,很好用,遍历效率不好说。
还是最流行的xml parser.

4:Tiny xml
感觉和微软的xml2很类似的说
// Parse the document
        CEGUITinyXML::TiXmlDocument doc;
        doc.Parse((const char*)buf);
        const CEGUITinyXML::TiXmlElement* currElement = doc.RootElement();
        if (currElement)
        {
            // function called recursively to parse xml data
            processElement(currElement);
        }



//

DOM,这是W3C的标准模型,它将XML的结构信息以树形的方式构建,提供了遍历这颗树的接口与方法。
SAX,一种低级的parser,逐元素的向前只读处理,不含有结构信息。
以上两种选择都各有利弊,但是都不是特别好的解决方案,它们的优缺点如下:

DOM

优点:易用性强,因为所有的XML结构信息都存在于内存中,并且遍历简单,支持XPath。
缺点:Parsing速度太慢,内存占用过高(原文件的5x~10x),对于大文件来说几乎不可能使用。
SAX

优点:Parsing速度快,内存占用不与XML的大小相联系(可以做到XML涨内存不涨)。
缺点:易用性差,因为没有结构信息,并且无法遍历,不支持XPath。如果需要结构的话只能读一点构造一点,这样的可维护性特别的差。
我们可以看出,基本上DOM与SAX是正好相反的两个极端,但是任何一个都不能很好的满足我们的大部分要求,我们需要找出另外一种处理方法来。注意XML的效率问题并不是XML本身的问题,而是处理XML的Parser的问题,就像我们在上面看到的两种方法有不同的效率权衡一样。


所谓的extractive parsing就是说在解析XML时,DOM或SAX会提取一部分原文件(一般来说是一个字符串),然后在内存中进行解析构建(输出自然就是一个或一些对象了)。
DOM与SAX都是extractive parsing模式,这种解析模式注定了DOM与SAX都需要大量的创建(销毁)对象,引起效率问题。

最新有一种VTD-xml parser的模式,类似于 解析2进制的视频流的快进快退
就像大多数好的产品一样,VTD-XML的原理并不复杂,而是很巧妙。为了实现non-extractive这个目的,它将原XML文件原封不动的以二进制的方式读进内存,连解码都不做,然后在这个byte数组上解析每个element的位置并把一些信息记录下来,之后的遍历操作便在这些保存下来的record上进行。

VTD-XML的record机制就叫做VTD(Virtual Token Descriptor),VTD将性能瓶颈在tokenization阶段就解决掉了真的是很巧妙很用心的做法。VTD是一个64bits长度的数值类型,记录了每个element的起始位置(offset),长度(length),深度(depth)以及token的类型(type)等信息。


posted @ 2008-03-28 14:53 vcommon 阅读(2501) | 评论 (0)编辑 收藏

CWGUI 的window类的头文件也有3000多行.复杂永远不能避免.

posted @ 2008-02-22 15:40 vcommon 阅读(192) | 评论 (0)编辑 收藏

TypeList 的Dispatech 好处和坏处
1:用处不大,
编译期决定将某些event送入某些处理函数,所以限制了函数一般会用全局的函数,更适合C语言
2优点
和delegate一样,在一个总的整体控制 的模式下,使外边看结构很简洁

只需要把相应的event发给control就可以了,而且control的扩展性很强,随意增加event和相应的处理


// Dispatech
 // TL为TypeList
 // F<int >为实现函数的类
 template<typename TL,template <int> class F,typename FUNC>
 class Dispetcher
 {
 map<int,FUNC> m_function;

 template<typename H>
 void Build()
 {
 pair<int,FUNC> t_pair;
 t_pair.first=H::Head::value;
 t_pair.second=F<H::Head::value>::Update;

 m_function.insert(t_pair);

 Build<H::Tail>();
 };
 template<>
 void Build<NullType>(){};
 public:
 Dispetcher()
 {
 Build<TL>();
 };
 FUNC GetFunc(int id)
 {
 map<int,FUNC>::iterator t_iterator;

 t_iterator=m_function.find(id);

 if (t_iterator!=m_function.end())
 return t_iterator->second;

 return NULL;;
 };
 };


typedef HRESULT (* TEST_FUNC)(long);


template<int>
class CEvent_Test
{
public:
 static HRESULT Update(long param);
};

void test()
{
typedef Typelist<Int2Type<EVENT_TEST>, ::NullType> typelist_eventtest;

 Dispetcher<typelist_eventtest,CEvent_Test,TEST_FUNC> disps;
}

posted @ 2008-02-20 17:22 vcommon 阅读(258) | 评论 (0)编辑 收藏

1:
dllwrap -mno-cygwin --target=i386-mingw32 --def libavcodec.def -o libavcodec.dll libavcodec/allcodecs.o libavcodec/mem.o libavcodec/common.o libavcodec/utils.o libavcodec/mpegvideo.o libavcodec/h263.o libavcodec/dsputil.o libavcodec/msmpeg4.o libavcodec/mpeg12.o libavcodec/h263dec.o libavcodec/rv10.o libavcodec/jrevdct.o libavcodec/simple_idct.o libavcodec/my_utils.o libavcodec/i386/cputest.o libavcodec/i386/dsputil_mmx.o libavcodec/i386/mpegvideo_mmx.o libavcodec/i386/idct_mmx.o libavcodec/i386/motion_est_mmx.o libavcodec/i386/simple_idct_mmx.o  -lmsvcrt -lcrtdll -L/lib/mingw
libavcodec/i386/motion_est_mmx.o:motion_est_mmx.c.text+0x9f3): undefined reference to `_bone'
libavcodec/i386/motion_est_mmx.o:motion_est_mmx.c.text+0xd33): undefined reference to `_bone'
libavcodec/i386/motion_est_mmx.o:motion_est_mmx.c.text+0xdb3): undefined reference to `_bone'
libavcodec/i386/simple_idct_mmx.o:simple_idct_mmx.c:(.text+0x21): undefined reference to `_wm1010'
libavcodec/i386/simple_idct_mmx.o:simple_idct_mmx.c:(.text+0x11c): undefined reference to `_d40000'
collect2: ld returned 1 exit status
dllwrap: gcc exited with status 1
make: *** [libavcodec.dll] Error 1
Project : error PRJ0019: 工具从"正在执行生成文件项目操作"
生成日志保存在“file://c:\cygwin\usr\src\ffdshow\src\ffmpeg\Release\BuildLog.htm”中


解决方法:
将bone wm1010 d40000的static标识去掉即可通过.
应该2005的编译器的原因


2:cygwin生成的dll --libavcodec.dll


3:
编译FFDSHOW
生成ffdshow.ax加入graphedt的时候
av_getVersion crash.
将编译生成的libavcodec.dllcopy到本C:\mydocuments\ffdshow\src\ffmpeg下成功
然后在TffDecoder * pNewObject = new TffDecoder(punk, phr);中crash

发现会从注册表里的设置里边加载codec

4:编译最新的FFDSHOW:
报错:error: more than one input file specified

type `nasm -h' for help

Project : error PRJ0019: 工具从"正在执行自定义生成步骤"


没有明显原因.
结论:路径中带有空格,更换路径.

报错: mismatch in operand sizes
使用nasm-0.98.38-win32,编译成功.使用最新nasm2.0才出现.

成功.

posted @ 2007-12-06 17:59 vcommon 阅读(2815) | 评论 (0)编辑 收藏

据说是因为vct3216.acm,vct3216.dll是安装在系统

目录下的反调试audio的组件导致.
更名,通过,可以调试了

posted @ 2007-11-10 11:00 vcommon 阅读(271) | 评论 (0)编辑 收藏

仅列出标题
共4页: 1 2 3 4