数据类型万能转换器boost,守护进度开篇

by admin on 2019年8月29日

写一个Windows上的守护进度(4)日志别的,windows守护进度

boost::lexical_cast为数值之间的转变(conversion)提供了全面方案,举例:将壹个字符串”123″转换成整数123,代码如下:

写一个Windows上的照应进度(1)开篇,守护进度开篇

boost::lexical_cast为数值之间的改造conversion)提供了完美方案,举个例子:将一个字符串”123″调换来整数123,代码如下:

写二个Windows上的护理进度(4)日志其他

本次把和日志相关的别样东西一并说了。

 

一、vaformat

C++日志接口平日有三种格局:流输入格局,printf方式。

自己动用printf格局,因为流输入倒霉调整格式。

printf方式须要日志接口协助不定长参数,小编并未有平昔在日记达成类里边辅助不定长参数,而是只接受二个字符串参数,能够崇敬第一篇。

干什么吧?

假使要产生不定长参数,就是如此

bool log_string(const LOG_LEVEL level, const char* file, const int line, const char *s, ...);

那么在每叁个log_xxx的变体里就都要写_vsnprintf_s那一套代码了,何况是一丝一毫等同的(小编不知晓__VA_ARGS__宏是不是能够传递),那眼看是不好的做法。

自身把不定长参数的拍卖放在了宏定义里,类似:

#define ErrorLog(s, ...) _Log(LOG_ERROR, __FILE__, __LINE__, vaformat(MAX_LOG_BUFFER, s, __VA_ARGS__))

vaformat正是管理不定长参数的:

std::string vaformat(const size_t max_size, const char* msg, ...);
std::wstring vaformat(const size_t max_size, const wchar_t* wmsg, ...);

因为并不知Doug式化后有多少长度,所以要内定最大尺寸,如若格式化后的长短抢先最大尺寸,则截断。vaformat里还也可能有三个小本事,当内定的max_size小于1024的时候,使用栈空间,否则申请堆内部存款和储蓄器,那是从std::string的完结中学来的——SSO短字符串优化。

能够看下vaformat的实现,四个本子的代码基本同样,那样自然是不佳的,但是作者不知情什么把她们联合起来,那是贰个todo。类似的难题上面还应该有。

 

二、CLastErrorFormat

那些东西是用来缓和第一篇里关系的记录LastErrorCode的题指标。

它的尤为重要功能便是把error
code转变到文本描述,合适的组织也足以省去GetLastError的调用:

class CLastErrorFormat : public boost::noncopyable
{
public:
    CLastErrorFormat()
        : m_code(GetLastError())
    {
    }

    CLastErrorFormat(const DWORD code)
        : m_code(code)
    {
    }

    ~CLastErrorFormat()
    {
    }

public:
    const DWORD code() const
    {
        return m_code;
    }

    const std::string& str()
    {
        //...
    }

    const std::wstring& wstr()
    {
        //...
    }

private:
    //...
};

日记达成类里对应的接口:

bool log_last_error(const LOG_LEVEL level, const char* file, const int line, CLastErrorFormat& e, const std::string& prefix);

接受一个CLastErrorFormat的引用,然后在笔录日志的时候,把error
code和其对应的描述也记录下来:xxx, error code: 999, error msg: yyy

提起底的日志接口是有多个本子的:二个经受三个CLastErrorFormat参数;另二个节约,在函数内部团结协会。

 

三、str_encode

自己不容许在日记文件里一会记宽字符串,一会记窄字符串,那就无助看了,又思索到日志文件的轻重缓急,小编最终决定,根据窄字符串SystemCurrentCodePage(在简体中文版的Windows上,正是GB2312)编码记录日志,所以对于宽字符串小编还要转变来窄字符串。

Windows提供了三个API来做编码转换:MultiByteToWideChar和WideCharToMultiByte,而那七个API总是要四遍调用技巧平平安安的转移。小编将其稍稍封装了一晃,做成了三个函数:

std::wstring multistr2widestr(const unsigned int from_code_page, const std::string& s);
std::string widestr2multistr(const unsigned int to_code_page, const std::wstring& ws, const char *default_char = NULL);

注:SystemCurrentCodePage的代码页编码正是CP_ACP。

这么在记宽字符串的时候总是会慢一些,所以笔者代码中,能用窄字符串的地方笔者都用窄字符串了。

 

四、any_数据类型万能转换器boost,守护进度开篇。lexical_cast

代码中年老年是免不了要做类型转变,特别是把数字转变到字符串,为了轻松一点,笔者利用了boost的lexical_cast,即使大家都说那货成效低,因为使用了C++的流,不过作者百折不挠“先正确,再优化”的规格,依旧选取了它。

只是,那些事物使用起来有两处不便:

  1. 改变退步的时候会抛非常

  2. 把bool转变到string的时候是0或1,不是true或false

 

为了缓和那四个难点,作者又做了一晃卷入:

  1. 更动退步的时候,填充为暗中同意值。调用者必需提供默许值

  2. 特化对于bool和string之间的转变

 

这就是any_lexical_cast:

template<typename Target, typename Source>
Target any_lexical_cast(const Source& src, const Target& fail_value)
{
    Target value = fail_value;
    try
    {
        value = boost::lexical_cast<Target>(src);
    }
    catch (boost::bad_lexical_cast&)
    {
        value = fail_value;
    }
    return value;
}

template<>
bool any_lexical_cast<bool, std::string>(const std::string& src, const bool& fail_value);

template<>
bool any_lexical_cast<bool, std::wstring>(const std::wstring& src, const bool& fail_value);

template<>
std::string any_lexical_cast<std::string, bool>(const bool& src, const std::string&);

template<>
std::wstring any_lexical_cast<std::wstring, bool>(const bool& src, const std::wstring&);

切实落到实处请参考源码。

 

五、CSelfPath

日记开始化接口日常须求提供三个路线参数,以钦命日志存放路线。笔者为其扩张了一个暗许路线:当传递空字符串时,将日志文件放在应用程序所在路径的log目录下,若log目录不设有,则先创设。

赢得应用程序所在门路本能够献身日志模块内部,但思索到其他地点也许也会用到,并且应用程序一旦运转,路径就不会变,所以就做成了叁个单例类CSelfPath。

CSelfPath仅在构造函数中调用GetModuleFileNameA二遍得到路线并分割成目录、文件名等等部分。

 

六、CLoggerImpl与Logger

日记的落实类里边有许多东西小编都不想给调用者看到,规范如private的分子;还会有日志达成类的接口并不易用。所以作者在日记完毕类和调用者之间又引入了二个直接层Logger,它的机要成效正是隐蔽日志达成类和使接口更“亲民”。当然除了这几个作者还给了它有个别别的成效:调控日志输出品级。Logger并不是二个类。

数据类型万能转换器boost,守护进度开篇。 

七、Disable 3rd party library warning

自个儿在采取boost关于string的algorithm的时候,发掘编写翻译器会大段的警戒,那缘于boost库中对std::copy的选择,而自己分明的接头boost库的这段代码是正确的。那一个警告又多又可恨,有没有平安的不二秘籍化解那几个警示?

没有什么可争辨的有了:

#pragma warning(push)
#pragma warning(disable:4996)
#include <boost/algorithm/string.hpp>
#pragma warning(pop)

上边的代码保存为二个头文件:boost_algorithm_string.h。今后要包蕴boost/algorithm/string.hpp时,均以boost_algorithm_string.h代替。

 

源码: (主)&&
(升高逼格用的)。

 

2016年二月1日礼拜六

bf88必发唯一官网,
写一个Windows上的医护进度(4)日志其余此次把和日志相关的任陈菲西一并说了。…

  1. string s = “123”;  
  2. int a = lexical_cast<int>(s); 

写贰个Windows上的医生和医护人员进度(1)开篇

不久前是因为职业必要,要写三个料理进度,首要正是要在被医护进程挂了的时候再把它启起来。提及来那几个效应是相比较简单的,不过笔者前说话写了重再次出现行反革命改过看起来比相当糟糕的代码,所以就想这一次写的天生丽质一点。写完后开掘,诶,还足以啊。于是就总括总计。

一.大约供给

  1. 效用——当被照望进度挂掉后再行启航它

  2. 可配备须要护理的历程

二.通盘考虑

  1. 为了防止重复造轮子,何况有的轮子或者自个儿也造不出来,上boost库

  2. 为了能够拿走较高的权能和能力所能达到开机自动运维,将其编写为贰个Windows服务

  3. 布署文件使用xml存款和储蓄,使用rapidxml库解析

4.
为了使其更具有通用性,作者又加了个效果与利益:实践周期职分。周期任务又分了两种,一种是时刻点任务,正是每到几点几分推行任务,另一种是时间距离职责,便是每隔多少分钟实行任务

三.先是个话题:日志模块

俗话讲,粮草未动,兵马先行。窃以为日志模块就如粮草同样,所以最初早先写日记模块。

只是有人会问日志模块这种轮子多得很,不是说好不重复造轮子的吗?这当然是有缘由的。

1.
自家所见过的日记模块无非就提供两种字符串Log接口,推行而知,在Windows上,大家平时会用到GetLastError去获取错误码,在此以前自个儿再而三写

ErrorLog("xxx fail, error code: %lu", GetLastError());

写得多了,就以为麻烦了,能或不能够简化一下?

2.
片段时候作者就想以前志文件里头记一段二进制数据,不管可不行读。不过从未一向记录字节数据的日志接口

3.
熟练Windows编制程序的同学都领悟,API有A/W之分,那是因为字符(串)参数有宽窄之分,有部分日志库根本就未有设想这么些,只提供char版本的接口,笔者假设想传入wchar_t的字符串,还得温馨再转一下,那写多了也麻烦啊

根据以上几点,作者主宰活动造轮子,要造三个舒舒服服的车轱辘。

以下是日志类的宣示:

class CLoggerImpl : public Singleton<CLoggerImpl>
{
    friend class Singleton<CLoggerImpl>;

private:
    CLoggerImpl();

public:
    ~CLoggerImpl();

public:
    //if dir is empty, use exe dir
    //when log file increases over max_size, we will create new log file
    //if max_size is 0, use 10 * 1024 * 1024 (10MB)
    bool init(const std::string& dir, const unsigned long max_size);
    bool init(const std::wstring& dir, const unsigned long max_size);

    bool log_string(const LOG_LEVEL level, const char* file, const int line, const std::string& s);
    bool log_string(const LOG_LEVEL level, const char* file, const int line, const std::wstring& ws);

    bool log_bytes(const LOG_LEVEL level, const char* file, const int line, const void *buf, const unsigned long len, const std::string& prefix);
    bool log_bytes(const LOG_LEVEL level, const char* file, const int line, const void *buf, const unsigned long len, const std::wstring& wprefix);

    bool log_last_error(const LOG_LEVEL level, const char* file, const int line, CLastErrorFormat& e, const std::string& prefix);
    bool log_last_error(const LOG_LEVEL level, const char* file, const int line, CLastErrorFormat& e, const std::wstring& wprefix);
};

请先关怀其接口,忽略别的部分。这里用了重载的点子解决调用者对char和wchar_t的区分。

四.结束语

自家说了算一点一点的说,本次就这么多2014年11月八日星期日

写三个Windows上的守护进度(1)开篇
这两天是因为职业需求,要写四个护理进度,首要就是…

string s = "123";  int a = lexical_cast<int>(s); 

这种方式特别轻松,作者刚强提出大家忘掉std大多的函数,直接采取boost::
lexical_cast。假若调换发生了竟然,lexical_cast会抛出贰个bad_lexical_cast十分,由在此在此之前后相继中须要对其开展捕捉。

这种方法非常轻松,小编猛烈提出大家忘掉std大多的函数,间接动用boost::
lexical_cast。借使转变发生了奇异,lexical_cast会抛出三个bad_lexical_cast卓殊,由在此之前后相继中供给对其展开捕捉。

明日入手

今后入手 编写如下程序,体验怎么样利用boost:: lexical_cast实现数值调换。
程序 4-11】使用boost:: lexical_cast实现指标数值调换

编制如下程序,体验怎么着使用boost:: lexical_cast达成数值调换。

01  #include "stdafx.h" 02    03  #include <iostream>  04  #include <boost/lexical_cast.hpp>  05    06  using namespace std;  07  using namespace boost;  08    09  int main()  10  {  11      string s = "123";  12      int a = lexical_cast<int>(s);  13      double b = lexical_cast<double>(s);  14    15      printf("%d\r\n", a + 1);  16      printf("%lf\r\n", b + 1);  17    18      try 19      {  20          int c = lexical_cast<int>("wrong number");  21      }  22      catch(bad_lexical_cast & e)  23      {  24          printf("%s\r\n", e.what());  25      }  26    27      return 0;28 } 

【程序 4-11】使用boost:: lexical_cast达成目的数值转变

如上程序实现字符串”123″到整数、双精度实数的调换为了防止程序作弊,大家特地让它将值加1),结果输出如图4-19所示。

  1. 01  #include “stdafx.h” 
  2. 02    
  3. 03  #include <iostream>  
  4. 04  #include <boost/lexical_cast.hpp>  
  5. 05    
  6. 06  using namespace std;  
  7. 07  using namespace boost;  
  8. 08    
  9. 09  int main()  
  10. 10  {  
  11. 11      string s = “123”;  
  12. 12      int a = lexical_cast<int>(s);  
  13. 13      double b = lexical_cast<double>(s);  
  14. 14    
  15. 15      printf(“%d/r/n”, a + 1);  
  16. 16      printf(“%lf/r/n”, b + 1);  
  17. 17    
  18. 18      try 
  19. 19      {  
  20. 20          int c = lexical_cast<int>(“wrong number”);  
  21. 21      }  
  22. 22      catch(bad_lexical_cast & e)
     
  23. 23      {  
  24. 24          printf(“%s/r/n”, e.what());  
  25. 25      }  
  26. 26    
  27. 27      return 0;28 } 
 
点击查看大图)图4-19  运行结果

如上程序达成字符串”123″到整数、双精度实数的退换(为了防范程序作弊,大家极度让它将值加1),结果输出如图4-19所示。

光盘导读 该项目相应于光盘中的目录”\ch04\LexicalCastTest”。

bf88必发唯一官网 1 以上摘自《把脉VC++》第4.6.2小节的剧情 ,转发请评释出处。

正文出自 “白乔博客”
博客,请必须保留此出处

strings= “123” ; int a=lexic…

 

 
(点击查看大图)图4-19  运行结果

 

光盘导读

该类型相应于光盘中的目录”/ch04/LexicalCastTest”。

===============================

bf88必发唯一官网 2

如上摘自《把脉VC++》第4.6.2小节的从头到尾的经过 ,转发请注解出处。

假定您想与本身沟通,请点击如下链接加我为好朋友:http://student.csdn.net/invite.php?u=113292&c=8913f87cffe7d533

 

from:

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图