﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-daiybh@ this-&gt;cppblog-随笔分类-c++</title><link>http://www.cppblog.com/daiybh/category/4842.html</link><description>我的，我的，还是我的！！</description><language>zh-cn</language><lastBuildDate>Wed, 21 May 2008 23:33:51 GMT</lastBuildDate><pubDate>Wed, 21 May 2008 23:33:51 GMT</pubDate><ttl>60</ttl><item><title>转一个log4cxx的教程 出处不明</title><link>http://www.cppblog.com/daiybh/archive/2008/01/25/41875.html</link><dc:creator>代李</dc:creator><author>代李</author><pubDate>Fri, 25 Jan 2008 03:31:00 GMT</pubDate><guid>http://www.cppblog.com/daiybh/archive/2008/01/25/41875.html</guid><wfw:comment>http://www.cppblog.com/daiybh/comments/41875.html</wfw:comment><comments>http://www.cppblog.com/daiybh/archive/2008/01/25/41875.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/daiybh/comments/commentRss/41875.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/daiybh/services/trackbacks/41875.html</trackback:ping><description><![CDATA[
<table width="100%">
<tbody>
<tr>
<td><img width="5" height="1" border="0" src=""/><br/>绿盟科技<br/>2003 年 9 月
<blockquote>
<p>log4cpp是个基于LGPL的开源项目，是基于优秀的日志处理跟踪项目Java语言的log4j移植过来的。log4j介绍的文档很多，在java领域使用的也比较广泛，而这个功能强大的库对国内的C++语言开发人员却使用的不多。这里从开发人员使用的角度介绍这个库，使开发人员用最少的代价尽快掌握这种技术。下面先简单介绍一下这个项目的优点（也是log4j的优点），然后分原理，手动使用步骤，配置文件驱动方式使用步骤，其他考虑等方面进行讨论。以下讨论基于log4cpp0.3.4b。</p>
</blockquote>
<p><a><span><span style="COLOR: #000000">0. 优点</span></span></a></p>
<div style="MARGIN-LEFT: 2em">提供应用程序运行上下文，方便跟踪调试；<br/>可扩展的、多种方式记录日志，包括命令行、文件、回卷文件、内存、syslog服务器、Win事件日志等；<br/>可以动态控制日志记录级别，在效率和功能中进行调整；<br/>所有配置可以通过配置文件进行动态调整；<br/>多语言支持，包括Java（log4j），C++（log4cpp、log4cplus），C（log4c），python（log4p）等；<br/>...<br/></div>
<p><a><span><span style="COLOR: #000000">1. 原理</span></span></a></p>
<p>log4cpp有3个主要的组件：categories（类别）、appenders（附加目的地）、和 layouts（布局）。（为了方便大家理解，文中尽量使用英文原词）</p>
<p>layout类控制输出日志消息的显示样式（看起来像什么）。log4cpp当前提供以下layout格式：</p>
<table cellpadding="5" bgcolor="#CCCCCC" cellspacing="0" border="1" width="100%">
<tbody>
<tr>
<td>
<pre xml:space="preserve">
<code>
log4cpp::BasicLayout     // 以"时间戳 优先级（priority，下文介绍）
                        // 类别（category，下文介绍）
     // NDC标签（nested diagnostic contexts 下文介绍）: 日志信息"。
              // 如：1056638652 INFO main : This is some info
log4cpp::PatternLayout  // 让用户根据类似于 C 语言 printf 函数的转换模式来指定输出格式。格式定义见代码附带文档。
log4cpp::SimpleLayout  // 以"优先级（priority） - 日志信息"格式显示。 
</code>
</pre></td>
</tr>
</tbody>
</table>
<p>appender类用来输出日志（被layout格式化后的）到一些设备上。比如文件、syslog服务、某个socket等。可以定义自己的 appender类输出日志信息到别的设备上，比如应用自身的日子处理进程、数据库等。appender和layout的关系是layout附在 appender上，appender类调用layout处理完日志消息后，记录到某个设备上。log4cpp当前提供以下appender：</p>
<table cellpadding="5" bgcolor="#CCCCCC" cellspacing="0" border="1" width="100%">
<tbody>
<tr>
<td>
<pre xml:space="preserve">
<code>
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 事件日志
</code>
</pre></td>
</tr>
</tbody>
</table>
<p>category 类真正完成记录日志功能，两个主要组成部分是appenders和priority（优先级）。优先级控制哪类日志信息可以被这个category记录，当前优先级分为：NOTSET, DEBUG, INFO, NOTICE, WARN, ERROR, CRIT, ALERT 或 FATAL/EMERG 。每个日志信息有个优先级，每个category有个优先级，当消息的优先级大于等于category的优先级时，这个消息才会被category记录，否则被忽略。优先级的关系如下。category类和appender的关系是，多个appender附在category上，这样一个日志消息可以同时输出到多个设备上。</p>
<p>NOTSET &lt; DEBUG &lt; INFO &lt; NOTICE &lt; WARN &lt; ERROR &lt; CRIT &lt; ALERT &lt; FATAL = EMERG</p>
<p>category被组织成一个树，子category创建时优先级缺省NOTSET，category缺省会继承父category的 appender。而如果不希望这种appender的继承关系，log4cpp允许使用additivity 标签，为false时新的appender取代category的appender列表。</p>
<p>为了更好的理解上面的概念下面以手动使用方式举例。</p>
<p><a><span><span style="COLOR: #000000">2. 手动使用步骤</span></span></a></p>
<p>手动使用log4cpp的基本步骤如下：</p>
<ol>
<li>实例化一个layout 对象；</li>
<li>初始化一个appender 对象；</li>
<li>把layout对象附着在appender对象上；</li>
<li>调用log4cpp::Category::getInstance("name"). 实例化一个category对象；</li>
<li>把appender对象附到category上（根据additivity的值取代其他appender或者附加在其他appender后）。</li>
<li>设置category的优先级；</li>
</ol>
<table cellpadding="5" bgcolor="#CCCCCC" cellspacing="0" border="1" width="100%">
<tbody>
<tr>
<td>
<pre xml:space="preserve">
<code>
// 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-&gt;setLayout(layout);

 // 4. 实例化一个category对象
 log4cpp::Category&amp; 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() &lt;&lt; "This will show up &lt;&lt; as " 
 &lt;&lt; 1 &lt;&lt; " critical message" 
 &lt;&lt; log4cpp::CategoryStream::ENDLINE;

 // clean up and flush all appenders
 log4cpp::Category::shutdown();
 return 0;
}
</code>
</pre></td>
</tr>
</tbody>
</table>
<p><a><span><span style="COLOR: #000000">3. 配置文件驱动方式使用步骤</span></span></a></p>
<p>另一个非常优秀的特征就是通过读取配置文件，确定category、appender、layout等对象。也是我们非常推荐的使用方式，可以灵活地通过配置文件定义所有地对象及其属性，不用重新编码，动态更改日志记录的策略。</p>
<p>Log4cpp主要提供了 log4cpp::PropertyConfigurator 和log4cpp::SimpleConfigurator两种机制（文件格式），但 log4cpp::SimpleConfigurator将来不再支持了，而且格式非常简单，这里就不多说明，自己看源码吧。</p>
<p>配置文件的格式和log4j的配置文件一样，是标准的java属性文件格式。下面是附带的例子配置文件：</p>
<table cellpadding="5" bgcolor="#CCCCCC" cellspacing="0" border="1" width="100%">
<tbody>
<tr>
<td>
<pre xml:space="preserve">
<code>
# 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 
</code>
</pre></td>
</tr>
</tbody>
</table>
<p>配置文件语法如下，不是很规范，结合上面的例子，应该可以看懂。</p>
<table cellpadding="5" bgcolor="#CCCCCC" cellspacing="0" border="1" width="100%">
<tbody>
<tr>
<td>
<pre xml:space="preserve">
<code>
  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
  </code>
</pre></td>
</tr>
</tbody>
</table>
<p>基本使用步骤是：</p>
<ol>
<li>读取解析配置文件；</li>
<li>实例化category对象；</li>
<li>正常使用这些category对象进行日志处理；</li>
</ol>
<p>下面是个简单的使用代码，使用起来是非常方便的：</p>
<table cellpadding="5" bgcolor="#CCCCCC" cellspacing="0" border="1" width="100%">
<tbody>
<tr>
<td>
<pre xml:space="preserve">
<code>
// 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&amp; f) {
  std::cout &lt;&lt; "Configure Problem " &lt;&lt; f.what() &lt;&lt; std::endl;
        return -1;
    }
 
 // 2 实例化category对象
 // 这些对象即使配置文件没有定义也可以使用，不过其属性继承其父category
 // 通常使用引用可能不太方便，可以使用指针，以后做指针使用
 // log4cpp::Category* root = &amp;log4cpp::Category::getRoot();
    log4cpp::Category&amp; root = log4cpp::Category::getRoot();
 
    log4cpp::Category&amp; sub1 = 
        log4cpp::Category::getInstance(std::string("sub1"));

    log4cpp::Category&amp; 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() &lt;&lt; "This will show up &lt;&lt; as " &lt;&lt; 1 &lt;&lt; " critical message" 
 &lt;&lt; log4cpp::CategoryStream::ENDLINE;
 sub3 &lt;&lt; log4cpp::Priority::ERROR 
              &lt;&lt; "And this will be an error"  
              &lt;&lt; log4cpp::CategoryStream::ENDLINE;
 sub3.log(log4cpp::Priority::WARN, "This will be a logged warning");
 
 return 0;
}
</code>
</pre></td>
</tr>
</tbody>
</table>
<p><a><span><span style="COLOR: #000000">4. 相关考虑</span></span></a></p>
<p>性能问题，可能是很多想使用log4cpp的程序员关心的问题。在参考资料2中有一段描述。结论就是log4j以及log4cpp是以性能为首要目标的；如果关闭日志记录的话，对性能影响可以忽略；打开日志记录，主要消耗是在记录动作，而不是库的管理过程；所以你尽可放心的使用。实在要深究性能的话。可以从下面方面提高：</p>
<p>输出的日志消息不要使用复杂的转换或者处理，比如： sub1.debug(string("Current num is") + i + GetCurStat()); 这种情况即使不进行日志处理，括号中的语句还是会执行。变通方法是：</p>
<table cellpadding="5" bgcolor="#CCCCCC" cellspacing="0" border="1" width="100%">
<tbody>
<tr>
<td>
<pre xml:space="preserve">
<code>
if(sub1.isDebugEnabled())
{
 sub1.debug(string("Current num is") + i + GetCurStat());
}
</code>
</pre></td>
</tr>
</tbody>
</table>
<p>安全性问题对于商业软件开发可能也是问题。可能不希望别人通过修改配置文件获取程序的调试等程序内部运行情况的日志信息。比较稳妥的方案或者是加密配置文件，运行中解密，输出到临时文件后读取；或者在发行版本里读取配置文件后，强行把低于某个优先级的category设到比较高的优先级。</p>
<p>多线程安全性问题。当前log4cpp还没有宣称自己是多线程安全的，不过其代码中大多数可能冲突的地方都增加了线程互斥控制，对多线程环境应该问题不大。但为了加入这个特性，linux下编译log4cpp时，configure请加入--with-pthreads 或者--with-omnithreads选项。Win版本已经加入对MS线程的支持。</p>
<p><a><span><span style="COLOR: #000000">5. 参考资料</span></span></a></p>
<p>1. Logging and Tracing in C++ Simplified: Traveling the Road Last Traveled by a Previously Invented Wheel<br/><a href="http://soldc.sun.com/articles/logging.html"><span style="TEXT-DECORATION: underline"><span style="COLOR: #0000ff">http://soldc.sun.com/articles/logging.html</span></span></a></p>
<p>2. log4j 提供了对日志记录的控制<br/><a href="http://www-900.ibm.com/developerWorks/cn/java/jw-log4j/index.shtml"><span style="TEXT-DECORATION: underline"><span style="COLOR: #0000ff">http://www-900.ibm.com/developerWorks/cn/java/jw-log4j/index.shtml</span></span></a></p>
<p>3. 使用Log4j进行日志操作<br/><a href="http://www-900.ibm.com/developerWorks/cn/java/l-log4j/index.shtml"><span style="TEXT-DECORATION: underline"><span style="COLOR: #0000ff">http://www-900.ibm.com/developerWorks/cn/java/l-log4j/index.shtml</span></span></a></p>
<p>4. log4cpp主页<br/><a href="http://sourceforge.net/projects/log4cpp/"><span style="TEXT-DECORATION: underline"><span style="COLOR: #0000ff">http://sourceforge.net/projects/log4cpp/</span></span></a></p>
<p>5. log4j主页<br/><a href="http://jakarta.apache.org/log4j/docs/index.html"><span style="TEXT-DECORATION: underline"><span style="COLOR: #0000ff">http://jakarta.apache.org/log4j/docs/index.html</span></span></a></p>
<p>6. log4cplus主页<br/><a href="http://log4cplus.sourceforge.net/"><span style="TEXT-DECORATION: underline"><span style="COLOR: #0000ff">http://log4cplus.sourceforge.net/</span></span></a></p>
<p>7. log4c主页<br/><a href="http://log4c.sourceforge.net/"><span style="TEXT-DECORATION: underline"><span style="COLOR: #0000ff">http://log4c.sourceforge.net/</span></span></a></p>
<p><a><span><span style="COLOR: #000000">6. 关于作者</span></span></a></p>
<p>李群，关注于网络安全产品的开发、研究；软件开发过程等方面。您可以通过<a href="mailto:liqun@nsfocus.com"><span style="TEXT-DECORATION: underline"><span style="COLOR: #0000ff">liqun@nsfocus.com</span></span></a>和他联系。</p>
</td>
</tr>
</tbody>
</table>
<img src ="http://www.cppblog.com/daiybh/aggbug/41875.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/daiybh/" target="_blank">代李</a> 2008-01-25 11:31 <a href="http://www.cppblog.com/daiybh/archive/2008/01/25/41875.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个空类编译器自动给其添加的函数有哪几个</title><link>http://www.cppblog.com/daiybh/archive/2007/12/25/39546.html</link><dc:creator>代李</dc:creator><author>代李</author><pubDate>Tue, 25 Dec 2007 01:11:00 GMT</pubDate><guid>http://www.cppblog.com/daiybh/archive/2007/12/25/39546.html</guid><wfw:comment>http://www.cppblog.com/daiybh/comments/39546.html</wfw:comment><comments>http://www.cppblog.com/daiybh/archive/2007/12/25/39546.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/daiybh/comments/commentRss/39546.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/daiybh/services/trackbacks/39546.html</trackback:ping><description><![CDATA[
<p><br/>一个空类编译器自动给其添加的函数有哪几个?</p>
<p><!--more--></p>
<p>class Empty<br/>{<br/>public:<br/>Empty(); // 缺省构造函数<br/>Empty( const Empty&amp; ); // 拷贝构造函数<br/>~Empty(); // 析构函数<br/>Empty&amp; operator=( const Empty&amp; ); // 赋值运算符<br/>Empty* operator&amp;(); // 取址运算符<br/>const Empty* operator&amp;() const; // 取址运算符 const<br/>};</p>
<img src ="http://www.cppblog.com/daiybh/aggbug/39546.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/daiybh/" target="_blank">代李</a> 2007-12-25 09:11 <a href="http://www.cppblog.com/daiybh/archive/2007/12/25/39546.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>动态调用dll中的导出类</title><link>http://www.cppblog.com/daiybh/archive/2007/10/11/33935.html</link><dc:creator>代李</dc:creator><author>代李</author><pubDate>Thu, 11 Oct 2007 03:49:00 GMT</pubDate><guid>http://www.cppblog.com/daiybh/archive/2007/10/11/33935.html</guid><wfw:comment>http://www.cppblog.com/daiybh/comments/33935.html</wfw:comment><comments>http://www.cppblog.com/daiybh/archive/2007/10/11/33935.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/daiybh/comments/commentRss/33935.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/daiybh/services/trackbacks/33935.html</trackback:ping><description><![CDATA[
<p>我们知道动态加载dll中的函数是用:<br/>LoadLibrary和GetProcAddress等函数.<br/>但是如何动态加载dll中的导出类呢?<br/>我平时只能用静态连接的方式h+lib</p>
<p>在网上找到的解决方法：<a href="http://www.codeguru.com/cpp/w-p/dll/importexportissues/article.php/c123/">http://www.codeguru.com/cpp/w-p/dll/importexportissues/article.php/c123/</a></p>
<br/><img src ="http://www.cppblog.com/daiybh/aggbug/33935.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/daiybh/" target="_blank">代李</a> 2007-10-11 11:49 <a href="http://www.cppblog.com/daiybh/archive/2007/10/11/33935.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转] cpp 开发常用工具荟萃</title><link>http://www.cppblog.com/daiybh/archive/2007/09/26/32902.html</link><dc:creator>代李</dc:creator><author>代李</author><pubDate>Wed, 26 Sep 2007 06:17:00 GMT</pubDate><guid>http://www.cppblog.com/daiybh/archive/2007/09/26/32902.html</guid><wfw:comment>http://www.cppblog.com/daiybh/comments/32902.html</wfw:comment><comments>http://www.cppblog.com/daiybh/archive/2007/09/26/32902.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/daiybh/comments/commentRss/32902.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/daiybh/services/trackbacks/32902.html</trackback:ping><description><![CDATA[
<p><span style="FONT-SIZE: 9pt"><strong>开发环境</strong><br/><br/>　　----＞Turbo c</span></p>
<p>　　DOS时代c语言开发的<a href="javascript:;" target="_self" onclick="javascript:tagshow(event, '%BE%AD%B5%E4');"><span style="TEXT-DECORATION: underline"><strong>经典</strong></span></a>工具，目前适合两类人使用：c语言beginner（尤其是学生一族），具有怀旧情节的专业人士：）</p>
<p>　　----＞Visual C++ 6.0/7.0</p>
<p>　　稳定而强大的IDE开发环境，具有丰富的调试功能，定制宏的功能也是其一大特色。Microsoft的经典之作，功能强大自不必言说。附带的一些工具也很不错，比如：Spy++。但编译器较之同类，支持c++标准的程度不够好，尤其6.0及以前的版本。</p>
<p>　　----＞BCB</p>
<p>　　Borland的C++ Builder是可以与VC匹敌的另一个功能强大的IDE，速度和稳定性稍逊，但对c++标准支持的程度较好。</p>
<p><br/>　　----＞Cygwin</p>
<p>　　Windows平台下的C++编译器，基于gcc，又完全兼容Window特有的东西，比如对winsock的支持。从<span style="COLOR: #4c408c">http://www.cygwin.com</span>可以找到有关Cygwin的详细信息。</p>
<p>　　----＞Dev-c++</p>
<p>　　Windows平台下，一个类似VC、BCB的c++ IDE开发环境，属于共享软件。界面亲切优雅，size也不大，其4.9.x版有中文语言支持，无需汉化。编译器基于gcc，完全支持STL。但是对于规模较大的软件项目，恐怕难以胜任。可以从:http://www.bloodshed.net/dev/devcpp.html找到有关Dev-c++的有关信息。</p>
<p>　　----＞Source Insight</p>
<p>　　有着和Dev c++一样漂亮的界面，提供代码的编辑和察看功能，具有丰富的语法加亮功能，可以像VC一样自动弹出成员函数的提示，并具有快速方便的函数跳转功能（但是跳转速度似乎有点慢）。只是默认设置不适合时，需要仔细的调整和修改。无法查找经typedef之后的名字。</p>
<p>　　<strong>辅助工具</strong></p>
<p>　　----＞Visual Assist</p>
<p>　　VC IDE环境下的辅助编程工具，能识别各种关键字、函数、成员变量，自动给出tip，并自动更正大小写错误，标示拼写错误等。是VC开发的良好伴侣。</p>
<p>　　----＞Understand for C++</p>
<p>　　一款c/c++IDE编程的辅助工具，支持反向工程，代码导向和一些统计功能，从<span style="COLOR: #4c408c">http://www.scitools.com</span>可以找到有关Understand for C++的详细信息。</p>
<p>　　<strong>程序编辑器</strong></p>
<p>　　----＞EditPlus</p>
<p>　　一款很不错的文本编辑软件，功能强大却又十分轻巧。支持不同语言的语法加亮，还有Project组织功能，具有丰富的自定义功能。通过设置User Tool，可以和其他语言编译器结合，形成一个简单的IDE。</p>
<p>　　----＞Ultra Edit</p>
<p>　　功能和EditPlus相当，通过脚本文件提供的配置功能可以定制编辑环境，但自6.0版以后一直没多大变化，就编程而言，自定义设置没有EditPlus方便。</p>
<p>　　----＞EMACS</p>
<p>　　公认的世界上功能最多，最复杂的文本编辑器，其实也可以当作程序员用的编辑器。</p>
<p>　　----＞Visual Slick Edit</p>
<p>　　一个功能强大的程序员用编辑器。最值得一提的是其定制功能，很好用，可以和EMACS相比。自带了一套PCODE解释器，用c的语法，还可以挂接动态库。配合mingw一起使用很方便。从<span style="COLOR: #4c408c">http://www.slickedit.com</span>可以找到有关SlickEdit的详细信息。</p>
<p>　　----＞IQEdit</p>
<p>　　全功能的程序员用编辑器，界面很漂亮，从<span style="COLOR: #4c408c">http://pwksoftware.com</span>可以找到有关IQEdit的详细信息。</p>
<p>　　<strong>UML/建模</strong></p>
<p>　　----＞Rational Rose</p>
<p>　　强大的建模工具，早已"家喻户晓"，功过自然不必多加评说了。从<span style="COLOR: #4c408c">http://www.rationalsoftware.com.cn</span>可以找到有关Rational Rose的详细信息。</p>
<p>　　----＞Visual Modeler</p>
<p>MS Visual Studio 6.0所附的小工具。属于Rational和MicroSoft合作的战略<a href="javascript:;" target="_self" onclick="javascript:tagshow(event, '%B2%FA%C6%B7');"><span style="TEXT-DECORATION: underline"><strong>产品</strong></span></a>，是Rose的简化版。<br/>----＞Visio</p>
<p>　　Microsoft的建模工具，感觉更人性化一些，但功能没有Rose多、强、专，支持正向的代码生成，以及对代码的反向工程。</p>
<p>　　----＞Together</p>
<p>　　另一款功能强大的建模工具，用java编写而成，口碑不错，不过速度稍稍慢了一些。从<span style="COLOR: #4c408c">http://www.togethersoft.com</span>可以找到有关Togather的详细信息，另外，以下网址提供了一个有关Together的教程： 　　　<span style="COLOR: #4c408c">http://www.cc.puv.fi/~tka/kurssit/Tietojarjestelmien_suunnittelu</span></p>
<p><span style="COLOR: #4c408c"><span style="TEXT-DECORATION: underline">/together/TCCGuide6</span></span></p>
<p>　　----＞Visual UML</p>
<p>　　支持多种语言类型，比如：VC、VB、DELPHI、CORBA IDL等，可以直接从UML设计图生成代码，简单易用，完全适合Personal use，界面也很清爽。从<span style="COLOR: #4c408c">http://www.visualObject.com</span>可以找到有关Visual UML的详细信息。</p>
<p>　　----＞SmartDraw</p>
<p>　　通用图表制作软件，可以用来制作组织机构图、流程图、统计图表等。随带有图库，基本满足制作各类图表的需要。从<span style="COLOR: #4c408c">http://www.smartdraw.com</span>可以找到有关SmartDraw的详细信息。</p>
<p>　　----＞PlayCase</p>
<p>　　国产面向对象的建模软件，兼容UML和IDEF，轻量级软件，只是界面看起来有点简朴，乃是高展先生用Delphi完成的。</p>
<p>　　<strong>版本控制</strong></p>
<p>　　----＞ClearCase</p>
<p>　　Rational的版本控制管理软件，功能强大，可以控制多种类型的文档，甚至包括Word、Excel、PowerPoint文档。但使用复杂，不易上手，且不是免费软件。</p>
<p>　　----＞CVS</p>
<p>　　为基于Web的分布式协同开发提供了版本控制管理手段，且是免费软件，可以通过脚本定制功能。但在权限控制方面功能相对较弱。</p>
<p>　　----＞VSS</p>
<p>　　微软的版本控制管理工具，功能相对简单，适合于小型团队开发，将其整合到微软的其他开发工具中，使用起来十分方便。</p>
<p>　　----＞SourceOffSite</p>
<p>　　微软为开发人员提供的远程访问VSS数据库的工具，使数据库得以远程更新，以支持远程办公。其他的版本管理工具还包括：PVCS、VCS、RCS等。</p>
<p>　　<strong>XML</strong></p>
<p>　　----＞expat</p>
<p>　　用于读取和处理XML文档的c函数库，最初是James Clark的个人作品，简单轻巧，且速度快。但支持的编码方式有限，最遗憾的是不支持中文。从<span style="COLOR: #4c408c">http://expat.sourceforge.net</span>可以找到有关expat的详细信息。</p>
<p>　　----＞xml4c</p>
<p>　　IBM的XML Parser，用c++语言写就，功能超级强大。号称支持多达100种字符编码，能够支持中文，适合于大规模的xml应用。若只是很小范围的应用，则非最佳选择，毕竟，你需要"背负"约12M左右的dll的沉重负担。从<span style="COLOR: #4c408c">http://www.alphaworks.ibm.com/tech/xml4c</span>可以找到有关xml4c的详细信息。</p>
<p>　　----＞Xerces c++</p>
<p>　　Apache的XML项目，同样是c++实现，来源于IBM的xml4c，因此编程接口也是和xml4c一致的。但是目前只支持少数的字符编码，如ASCII，UTF-8，UTF-16等，不能处理包含中文字符的XML文档。从<span style="COLOR: #4c408c">http://xml.apache.org/xerces-c</span>可以找到有关Xerces c++的详细信息。</p>
<p>　　<strong>测试</strong></p>
<p>　　----＞CppUnit</p>
<p>　　一个c++的单元测试框架，可以通过派生测试类的方式，定制具体的测试方案。xUnit家族的一员，从JUnit移植而来，JUnit是Java语言的单元测试框架。从<span style="COLOR: #4c408c">http://cppuint.sourceforge.net</span>可以找到有关CppUint的详细信息。</p>
<p>　　----＞Rational ROBOT</p>
<p>　　Rational的自动化测试工具，通过编写脚本的方式提供自动化测试特性。其GUI方式的脚本录制功能，有助于对GUI软件进行功能测试；其VU方式的脚本录制功能，有助于测试某些软件的数据通讯功能。</p>
<p>　　----＞Rational Purify</p>
<p>　　同样是Rational的自动化测试工具，不需要被测程序的源代码，可以用来检查内存访问错误、Windows API调用错误等，以完成软件的可靠性测试，属于白盒测试。</p>
<p>　　其他的Rational测试工具还包括：TestFactory、PureCoverage、TestManager等。</p>
<p>　　<strong>日志</strong></p>
<p>　　----＞log4cpp</p>
<p>　　一个用于日志记录的c++函数库，可以将内容以定制的方式记录到不同的目的地，比如：文件、控制台syslog等，同时还可以通过控制记录级别来屏蔽掉某些无关记录。从<span style="COLOR: #4c408c">http://log4cpp.sourceforge.net</span>可以找到有关log4cpp的详细信息。</p>
<p>　　<strong>注释</strong></p>
<p>　　----＞Doc++</p>
<p>　　注释文档生成工具，根据源程序中的文档注释，可以输出TeX和HTML格式的文档。除了支持c/c++语言外，还支持IDL和java。仅提供命令行使用方式。从<span style="COLOR: #4c408c">http://docpp.sourceforge.net</span>可以找到有关Doc++的详细信息。</p>
<p>　　----＞Doxygen</p>
<p>　　注释文档生成工具，较之Doc++功能更为齐全，可以生成包括HTML、PDF、RTF在内的多种格式的文档，并有GUI界面，除了支持c/c++语言外，还支持IDL、java、PHP、c#等。从<span style="COLOR: #4c408c">http://www.stack.nl/~dimitri/doxygen</span>可以找到有关Doxygen的详细信息。</p>
<img src ="http://www.cppblog.com/daiybh/aggbug/32902.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/daiybh/" target="_blank">代李</a> 2007-09-26 14:17 <a href="http://www.cppblog.com/daiybh/archive/2007/09/26/32902.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[zt]挺好玩的C语句</title><link>http://www.cppblog.com/daiybh/archive/2007/08/06/29443.html</link><dc:creator>代李</dc:creator><author>代李</author><pubDate>Mon, 06 Aug 2007 09:47:00 GMT</pubDate><guid>http://www.cppblog.com/daiybh/archive/2007/08/06/29443.html</guid><wfw:comment>http://www.cppblog.com/daiybh/comments/29443.html</wfw:comment><comments>http://www.cppblog.com/daiybh/archive/2007/08/06/29443.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/daiybh/comments/commentRss/29443.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/daiybh/services/trackbacks/29443.html</trackback:ping><description><![CDATA[
<p>转自<a href="http://blog.vckbase.com/lishengg_blog/" target="_blank">紫罗兰茶馆</a></p>
<p>我在学习VC,或者在阅读别人写的文章的时候,偶尔碰到下面很多有趣的,并且很奇怪的语句,整理起来,以备后忘. 其实有些是不大容易想到的技巧，贴出来权当大伙饭后没事的小品文，当然不要过多的看重类似的语句学习，而忽略了基础知识。<br/></p>
<p>一. 奇怪的宏定义<br/>(1) #define for if(0); else for<br/>按照c++标准,for中定义的变量的作用域应该只在for循环中有效,而VC却不行,比如这样定义是不对的<br/>for(int i=0;i&lt;90;i++)<br/>{<br/>...;<br/>}</p>
<p>for(int i=0;i&lt;90;i++) //重复定义i变量<br/>{<br/>...;<br/>}</p>
<p>如果加上标题的那句,那么就可以了,就是让i作用域局限在else中. 这个问题在net中已经得到解决。</p>
<p><br/>二、宏定义怪圈<br/>#define wait_event(wq,condition) \<br/>do{ \<br/>if(condition) \<br/>break; \<br/>__wait_event(wq,condition); \<br/>}while(0)</p>
<p><br/>明明这句话只执行一次,为什么还还用do-while语句呢?</p>
<p>假设有这样一个宏定义<br/>#define macro(condition) \<br/>if(condition) dosomething();<br/>现在在程序中这样使用这个宏：<br/>if(temp)<br/>macro(i);<br/>else<br/>doanotherthing();<br/>一切看起来很正常，但是仔细想想。这个宏会展开成：<br/>if(temp)<br/>if(condition) dosomething();<br/>else<br/>doanotherthing();<br/>这时的else不是与第一个if语句匹配，而是错误的与第二个if语句进行了匹配，编译通过了，但是运行的结果一定是错误的。为了避免这个错误，我们使用do{….}while(0) 把它包裹起来，成为一个独立的语法单元，从而不会与上下文发生混淆。同时因为绝大多数的编译器都能够识别do{…}while(0)这种无用的循环并进行优化，所以使用这种方法也不会导致程序的性能降低。<br/>这个用法在linux源码中很常见。</p>
<p>三、功能强大的解释<br/>除了/* */和 //解释以外，你见过这样的解释方法了吗？<br/>#if(0)<br/>........<br/>#endif</p>
<p>这样是为了解释掉某段程序,而不影响其中的/*...*/的作用,便于调试，而/*.....*/是不能嵌套的,编译会出错.</p>
<p>四、数组变脸 a[i]和i[a]<br/>在程序里本应该用a[i]，但i[a]竟然和a[i]输出的结果一样。为什么。今天把问题整理如下：<br/>i[a]是标准语法。"[]"称为下标运算符，其语法为：<br/>postfix_expression [ expression ]<br/>其中"postfix_expression"和"expression"之中必须有一个是指针类型（或数组），而另一个是整型。<br/>例如下面的程序是完全合法的：<br/>int a[]={0,1,2,3,4};<br/>printf("%d\n",3[a]);<br/>下标运算符参与的表达式在求解时仅仅是做一个变换而已，将"postfix_expression [ expression ]"<br/>改写为" * ( postfix_expression + expression ) "，因此a[3]和3[a]分别改写为*(a+3)和*(3+a)，<br/>可见二者是完全等价的。但注意不要用i[a]这种形式，因为它不符合日常习惯。<br/>实验代码：<br/>#include "stdafx.h"<br/>#include "iostream.h"<br/>int f();<br/>int main(int argc, char* argv[])<br/>{</p>
<p>int a[20]={1,2,3,4,5,6,7,8,9};<br/>cout&lt;&lt;a[f()]&lt;&lt;endl;<br/>cout&lt;&lt;f()[a]&lt;&lt;endl;<br/>return 0;<br/>}</p>
<p>int f()<br/>{<br/>return 4;<br/>}</p>
<p>实验结果：<br/>4<br/>4<br/>Press any key to continue</p>
<p>五、双胞胎定义和声明：int x;x;</p>
<p>这儿是个关于宏的问题，我曾用过ATL的串转换宏，包括W2A，开始有些东西我还不太明白。为了使用这些宏，必须在函数的开始处用USES_CONVERSION来初始化某些局部变量。用就用吧，但是看看这个宏的定义，它有类似下面的代码：</p>
<p>// 在atlconv.h文件中<br/>#define USES_CONVERSION \<br/>int _convert; _convert; \<br/>UINT _acp = GetACP(); _acp; \<br/>LPCWSTR _lpw; _lpw; \<br/>LPCSTR _lpa; _lpa</p>
<p>为什么它们用"int x;x;"--这种后面跟着变量的声明？</p>
<p>很多人都碰到过这个令人困惑的问题，后来发现简单的答案是：禁止编译器的警告信息（warning）。如果单独有一行代码：<br/>int x;<br/>且从来没有使用过x，那么编译器汇报错"unreferenced local variable：x",意思是未引用过的局部变量x，如果将警告信息的输出<br/>调到最大。为了避免讨厌的警告，USES_CONVERSION引用声明的变量。</p>
<p>int x; // 声明<br/>x; // 使用这个变量</p>
<p>在C++之前的时代，程序员有时在C中用函数形参做同样的事情来避免"unreferenced formal parameter"或其它的深奥费解的编译错误。</p>
<p>void MyFunc(int x, char y)<br/>{<br/>x;<br/>y;<br/>…<br/>}</p>
<p>当然，现在用下面的代码可以更有效地完成同样的事情：</p>
<p>// 参数 x 不是用<br/>void MyFunc(int /* x */)<br/>{<br/>…<br/>}</p>
<img src ="http://www.cppblog.com/daiybh/aggbug/29443.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/daiybh/" target="_blank">代李</a> 2007-08-06 17:47 <a href="http://www.cppblog.com/daiybh/archive/2007/08/06/29443.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>