存档

文章标签 ‘c++’

c++点滴:string非空判断和随机访问的实现细节和使用方法

2017年10月17日 没有评论
  1. 非空判断
    • 一般通过是否等于”” 或者empty()函数的返回值来判断是否为空,结果是一致的
    • 差别在于:empty()返回的是string内置变量_M_rep()->_M_length的值,不需要其他计算;而与””比较是需要调用compare(const _CharT* __s)函数来判断的,因此在性能方面,empty()更占优
  2. 随机访问
    • 可通过[]或at()来随机访问,都是通过下标直接访问内部buffer,很快。_M_data()[__pos]
    • 差别在于:at()更安全。当下标超出string.size()时,at()抛出异常,而[]则引发断言错误。
分类: C/C++, 开发 标签:

分享一段解析HTTP请求消息头的C++代码

2017年10月16日 没有评论

Http请求消息说白了就是\r\n和:分割的一串字符,解析消息头部考察的是基本的字符串操作。当然实际应用中可以使用boost::splitl来辅助处理。

请求消息如下:

GET /suggest?word=http://t.&callback=suggest360&encodein=utf-8&encodeout=utf-8&_h=18.js&outfmt=json HTTP/1.1
Host: sug.so.360.cn:8188
Cache-Control: no-cache
Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36 QIHU 360SE
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8
Accept: */*
Cookie: vjuids=a8f919aab.156c5a83b9b.0.3db0cfd7; shenhui12=w:1; gn12=w:1; sci12=w:1; UM_distinctid=15c7168d4207f-083dc20ce-4349052c-100200-15c7168d42346; sohutag=8HsmeSc5NSwmcyc5NSwmYjc5MSwmYSc5NywmZjc5NCwmZyc5NCwmbjc5NjwmaSc5NSwmdyc5NCwmaCc5NCwmYyc5NCwmZSc5NCwmbSc5NCwmdCc5NH0; _muid_=1501816572977065; _ga=GA1.2.1163329499.1503043055; beans_mz_userid=62mbb0GPSAy5; debug_test=sohu_third_cookie; lastpopup=2017-8-19; vjlast=1472194952.1505800087.21; IPLOC=CN1100; SUV=1608221725397504
Range: bytes=17276560-19912545
Referer: http://offp.download.icartoons.cn:8188/client_package/v_4125/7825

解析代码如下:

//存储请求行
string cmdLine="";  
//存储消息头各字段和值
map<string, string> kvs;  

size_t pos=0, posk=0, posv=0;
string k="", v="";
char c;
//http保存了上述GET请求
while(pos != http.size())  
{
    c=http.at(pos);
    if(c == ':')
    {
        //非请求行,且消息头名称未解析
        if(!cmdLine.empty() && k.empty())  
        {
            //存储消息头名称
            k = http.substr(posk, pos-posk);  
            //跳过冒号和空格
            posv = pos+2;  
        }
    }
    //行尾
    else if(c == '\r' || c=='\n')  
    {
        //尚未解析到消息头字段名称,且请求行也未解析过
        if(k.empty() && cmdLine.empty())  
        {
            //本行应是请求行,保存之
            cmdLine = http.substr(posk, pos-posk);  
        }
        else
        {
            //已解析了消息头字段名称,尚未解析字段值
            if(!k.empty() && v.empty())  
            {
                //存储字段值
                v = http.substr(posv, pos-posv);  
            }
        }
        posk=pos+1;
    }

    if(!k.empty() && !v.empty() && !cmdLine.empty())
    {
        //保存消息头字段名称和值
        kvs.insert(make_pair(k,v));  
        k="";
        v="";
    }
    ++pos;
}

需要注意的是:消息头各字段的值中也有可能出现冒号。

分类: C/C++, 开发 标签: ,

hiredis处理zscan和hscan的reply

2015年11月6日 没有评论

zscan的返回值可以看做是一个二维数组,第一维包含两个元素:string类型的游标cursor和集合元素数组;第二维即集合元素数组,这个数组交替存放着集合元素和score,元素和score也都是string类型的。当然所有的值都是通过指针来引用的,所以使用时务必小心。

当cursor为0时表示,扫描结束;非0的cursor值用来进行后续扫描。

集合元素数组reply->elements指示当前数组中包含多少个元素(指针),据此来遍历整个数组。

示例代码如下:

//cLocal points to the local redis

llCursor=0;

done=false;

while(!done)

{

cmd=”zscan “+setName+” %lld count 10″;
reply = (redisReply *)redisCommand(cLocal, cmd.c_str(), llCursor);
if(reply == NULL)
{
cout << “scan ” << setName << “failed, error is: ” << cLocal->errstr;
redisFree(cLocal);
cLocal = NULL;
break;
}

if(reply->type == REDIS_REPLY_ARRAY)
{
if(reply->elements == 0)
{
done=true;
cout << “get 0 msg from ” << setName;
}
else
{
llCursor=boost::lexical_cast<long long>(reply->element[0]->str);  //reply->element[0] contains cursor

redisReply ** siteCounters=reply->element[1]->element;               //reply->element[1] contains elements array:value1,score1,value2,score2,…
for(size_t i=0; i<reply->element[1]->elements; i++)
{
string elem = siteCounters[i++]->str;
string score = siteCounters[i]->str;

}
if(llCursor == 0)  //scan over
{
done=true;
}
}
}
else
{
done=true;
}
freeReplyObject(reply);

}

hscan和zscan api的用法一样。

分类: C/C++, Redis 标签: , , , , ,

c代码中执行shell命令的方法

2015年9月18日 没有评论
  1. 使用system
  2. 使用popen,可以获取shell的输出

FILE * fp = popen(cmd.c_str(), “r”);
if(fp == NULL)
{
cout << “popen failed to excute ” << cmd;
return 1;
}

 

string out;

while(!feof(fp))

{

char buffer[1024] = {0};

fgets(buffer, sizeof(buffer), fp);

out += buffer;

}
pclose(fp);
cout << cmd << “, output is: ” << out;

return 0;

分类: C/C++, 资料 标签: , ,

Hiredis: redis c client使用注记

2015年9月17日 没有评论
  1. 编译
  2. 使用
    • 初始化
    • 连接redis数据库

      redisContext * pConn = redisConnect(redisIp.c_str(), redisPort);
      if (m_cLocal == NULL)
      {
      return 1;
      }

      if(pConn->err)
      {
      cout << “Connection to redis[” << redisIp << “] error: ” << pConn->errstr;
      redisFree(pConn);
      return 2;
      }

    • 执行命令

      string cmd=”set foo bar;
      redisReply * reply=(redisReply *)redisCommand(pConn, cmd.c_str());
      if(reply == NULL)
      {
      cout << “redis[” << redisIp << “] excute ” << cmd << ” failed, error is: ” << pConn->errstr;
      redisFree(pConn);
      pConn=NULL;
      return 3;
      }
      freeReplyObject(reply);

    • 解析结果
      • 不同的命令返回不同类型的结果,需要根据reply->type字段进行解析
      • reply->type主要有以下6种,可嵌套,比如array类型的结构中包含指向其他array的指针

        #define REDIS_REPLY_STRING 1
        #define REDIS_REPLY_ARRAY 2
        #define REDIS_REPLY_INTEGER 3
        #define REDIS_REPLY_NIL 4
        #define REDIS_REPLY_STATUS 5
        #define REDIS_REPLY_ERROR 6

      • 由于返回结果通过指针来引用,操作时需要格外小心
  3. 注意事项
  • Once an error is returned the context cannot be reused and you should set up a new connection.

上面示例中执行命令时,如果返回了错误,则连接不可用,需要重新建立连接。

  • redisCommand这个函数的用法应参照c中的printf。上面示例中,如果cmd中含%,特别要引起注意!
分类: C/C++, Redis, 数据库, 资料 标签: , , , ,

boost常用库之program_options

2015年9月10日 没有评论

C++标准库本身不提供处理命令行参数的类,通常情况下需要手动“造轮子”。感谢boost,我们有了progam_options这个好用的类库。

  1. program_options简介该库允许开发者从命令行或者文件中获取(name,value)形式的程序选项,比如./mypro -P1 param1 –p2 param2。
    相较于自己手写代码处理程序参数,使用program_options具有以下优点:

    • 简单:库体积小巧,声明程序选项语法简单,自动转换选项值的类型并存储到变量中;
    • 更好的错误报告;
    • 可从任何地方读取选项:不仅限于命令行,文件甚至环境变量亦可,而这并不需要额外的代码量;
  2. 如何使用?
    • 确认编译boost生成了libboost_program_options.so库文件,并且确认头文件/boost/program_options.hpp存在。否则什么都干不了~
    • 源文件中#include <boost/program_options.hpp>
    • makefile中链接选项加入-lboost_program_options,当然编译选项include目录也得能找到program_options.hpp
  3. 例子

    //命名空间缩略名
    namespace po = boost::program_options;
    try {
    //使用类options_description声明程序选项描述信息
    po::options_description desc(“Allowed options”);
    //add_options方法用于声明选项信息,包括选项名称、值的信息(类型,默认参数等)、选项描述信息
    string filter;
    desc.add_options()
    (“help”, “produce help message”) //名称、描述
    “compression”, po::value<int>(), “set compression level”) //名称、值类型、描述
    (“filter,F”, po::value<string>(&filter)->default_value(“tcp port 80″), “set pcap filter”) //名称、值类型和默认参数、描述
    ;
    //从命令行解析并存储程序选项
    po::variables_map vm;
    po::store(po::parse_command_line(ac, av, desc), vm);
    po::notify(vm);
    //读取选项
    if (vm.count(“help”)) {
    cout << desc << “\n”; return 1;
    }
    if (vm.count(“compression”)) {
    cout << “Compression level was set to ” << vm[“compression”].as<int>() << “.\n”;
    }
    else {
    cout << “Compression level was not set.\n”;
    }
    }
    catch(…) {
    }

  4. 更多内容可参考Boost.Program_options
分类: C/C++ 标签: ,

部分编译安装boost

2015年7月1日 1 条评论

完整编译boost库需要很长时间,而且我们不一定会用到所有的库。那么如何只编译只需要的库呢?

  1. 解压boost源码,进入解压后的目录
  2. ./bootstrap.sh生成bjam
  3. ./bjam –build-type=complete –layout=versioned –toolset=gcc –with-thread –with-regex #–with指定所需要的模块
  4. ./bjam install #安装到默认路径下
分类: C/C++, 开发, 资料 标签: , ,

c++学习资料收集

2015年6月30日 没有评论

c++,重量级的编程语言!运行效率高,应用范围广:系统底层、服务器软件、桌面应用…但是众多语言中也是最不易掌握的一个。

语言层面,定义规范,内容丰富,需要长时间不断的学习琢磨。

这里收集一些c++学习资料,长期更新。

C++官网

C++ Primer第四版

分类: C/C++, 语言 标签: , ,