bookmark_borderc++11 function和bind使用简介

bind

定义在头文件 functional 里

template<typename _Func, typename... _BoundArgs>inline typename
_Bind_helper<__is_socketlike<_Func>::value, _Func, _BoundArgs...>::type
bind(_Func&& __f, _BoundArgs&&... __args)

template<typename _Result, typename _Func, typename... _BoundArgs>inline
typename _Bindres_helper<_Result, _Func, _BoundArgs...>::type
bind(_Func&& __f, _BoundArgs&&... __args)

函数模板 bind 生成 f 的转发调用包装器。调用此包装器等价于以一些绑定到 args 的参数调用 f 。类似于 python 的 functools.partial

参数 f 表示可调用对象(函数对象、指向函数指针、函数的引用、指向成员函数指针或指向数据成员指针)

参数 __args 表示要绑定的参数列表。未绑定参数使用命名空间 std::placeholders 的占位符 _1, _2, _3... 所替换

需要注意的是:

调用指向非静态成员函数指针或指向非静态数据成员指针时,首参数必须是引用或指针(可以包含智能指针,如 std::shared_ptr 与 std::unique_ptr),指向将访问其成员的对象。

到 bind 的参数被复制或移动,而且决不按引用传递,除非包装于 ref 或 cref

允许同一 bind 表达式中的多重占位符(例如多个 _1 ),但结果仅若对应参数( u1 )是左值或不可移动右值才良好定义。

function

定义在头文件 functional 里

template<typename _Res, typename... _ArgTypes>class function<_Res(_ArgTypes...)>

类模板 std::function 是通用多态函数封装器。 std::function 的实例能存储、复制及调用任何可回调目标——函数、lambda表达式、bind表达式、其他函数对象,还可以指向成员函数指针和指向数据成员指针。

存储的可调用对象被称为 std::function 的目标。若 std::function 不含目标,则称它为。调用 std::function 的目标导致抛出 bad_function_call 异常。

function 满足可复制构造和可复制赋值。

function的用法:

1. 保存普通函数

void printA(int a)
{
     cout << a << endl;          
}

std::function<void(int a)> func;
func = printA;
func(2);   //2

2. 保存lambda表达式

std::function<void()> func_1 = [](){cout << "hello world" << endl;};    
func_1();  //hello world

3. 保存成员函数

class Foo{
    Foo(int num) : num_(num){}    void print_add(int i) const {cout << num_ + i << endl;}    int num_;  
};//保存成员函数std::function<void(const Foo&,int)> f_add_display = &Foo::print_add;
Foo foo(2);
f_add_display(foo,1);

关于bind的用法:

可将bind函数看作是一个通用的函数适配器,它接受一个可调用对象,生成一个新的可调用对象来“适应”原对象的参数列表。

调用bind的一般形式:auto newCallable = bind(callable,arg_list);

其中,newCallable本身是一个可调用对象,arg_list是一个逗号分隔的参数列表,对应给定的callable的参数。即,当我们调用newCallable时,newCallable会调用callable,并传给它arg_list中的参数。

arg_list中的参数可能包含形如_n的名字,其中n是一个整数,这些参数是“占位符”,表示newCallable的参数,它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对象中参数的位置:_1为newCallable的第一个参数,_2为第二个参数,以此类推。 from 《C++ primer》第五版

#include <iostream>#include <functional>using namespace std;class A
{public:    void fun_3(int k,int m)
    {
        cout<<"print: k="<<k<<",m="<<m<<endl;
    }
};void fun_1(int x,int y,int z)
{
    cout<<"print: x=" <<x<<",y="<< y << ",z=" <<z<<endl;
}void fun_2(int &a,int &b)
{
    a++;
    b++;
    cout<<"print: a=" <<a<<",b="<<b<<endl;
}int main(int argc, char * argv[])
{    //f1的类型为 function<void(int, int, int)>
    auto f1 = std::bind(fun_1,1,2,3); //表示绑定函数 fun 的第一,二,三个参数值为: 1 2 3
    f1(); //print: x=1,y=2,z=3
    auto f2 = std::bind(fun_1, placeholders::_1,placeholders::_2,3);    //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别由调用 f2 的第一,二个参数指定
    f2(1,2);//print: x=1,y=2,z=3 
    auto f3 = std::bind(fun_1,placeholders::_2,placeholders::_1,3);    //表示绑定函数 fun 的第三个参数为 3,而fun 的第一,二个参数分别由调用 f3 的第二,一个参数指定    //注意: f2  和  f3 的区别。
    f3(1,2);//print: x=2,y=1,z=3

    int m = 2;    int n = 3;
    auto f4 = std::bind(fun_2, placeholders::_1, n); //表示绑定fun_2的第一个参数为n, fun_2的第二个参数由调用f4的第一个参数(_1)指定。
    f4(m); //print: m=3,n=4
    cout<<"m="<<m<<endl;//m=3  说明:bind对于不事先绑定的参数,通过std::placeholders传递的参数是通过引用传递的,如m
    cout<<"n="<<n<<endl;//n=3  说明:bind对于预先绑定的函数参数是通过值传递的,如n    
    A a;    //f5的类型为 function<void(int, int)>
    auto f5 = std::bind(&A::fun_3, a,placeholders::_1,placeholders::_2); //使用auto关键字
    f5(10,20);//调用a.fun_3(10,20),print: k=10,m=20
    std::function<void(int,int)> fc = std::bind(&A::fun_3, a,std::placeholders::_1,std::placeholders::_2);
    fc(10,20);   //调用a.fun_3(10,20) print: k=10,m=20 
    return 0; 
}

bookmark_border一个使用Poco::http库封装的c++ http调用类

头文件webapi.h

#pragma once
#include <Poco/Net/HTTPClientSession.h>
#include <Poco/Net/HTTPRequest.h>
#include <Poco/Net/HTTPResponse.h>
#include <Poco/StreamCopier.h>
#include <Poco/Net/NetException.h>
#include <Poco/Net/HTMLForm.h>
#include <Poco/URI.h>
#include <Poco/NumberParser.h>
#include <Poco/String.h>
#include <atomic>
#include <string>

using namespace std;

class CWebApi
{
public:
	CWebApi(string baseUrl = "");
	~CWebApi();

	void setBaseUrl(const string& baseUrl);
	string getBaseUrl();
	bool httpGet(string api, string& resp, int32_t& status, string& errmsg);

private:
	string baseUrl_;
};

源文件webapi.cpp

#include "webapi.h"
#include <iostream>
#include "log.h"

CWebApi::CWebApi(string baseUrl)
	:baseUrl_(baseUrl)
{

}

CWebApi::~CWebApi()
{

}

void CWebApi::setBaseUrl(const string& baseUrl)
{
	baseUrl_ = baseUrl;
}

string CWebApi::getBaseUrl()
{
	return baseUrl_;
}

bool CWebApi::httpGet(string api, string& resp, int32_t& status, string& errmsg)
{
	LOG_INFO("BEGIN {}", api);

	bool ret = false;
	string strUrl;
	
	strUrl = baseUrl_ + api;

	try {

		Poco::URI httpUrl(strUrl);
		Poco::Net::HTTPClientSession session(httpUrl.getHost(), httpUrl.getPort());
		session.setTimeout(Poco::Timespan(8, 0), Poco::Timespan(8, 0), Poco::Timespan(8, 0));
		Poco::Net::HTTPRequest httpReq(Poco::Net::HTTPRequest::HTTP_GET, httpUrl.getPathAndQuery());
				
		httpReq.add("Connection", "close");
		session.sendRequest(httpReq);

		Poco::Net::HTTPResponse httpResp;
		istream& is = session.receiveResponse(httpResp);
		Poco::StreamCopier::copyToString(is, resp);
		status = httpResp.getStatus();

		if (status == Poco::Net::HTTPResponse::HTTP_NOT_MODIFIED) 
		{
			LOG_DEBUG("WebAPI {}, configuration not modified!", strUrl);
		}

		if (status == Poco::Net::HTTPResponse::HTTP_OK
			|| status == Poco::Net::HTTPResponse::HTTP_NOT_MODIFIED)
		{

			ret = true;
		}
		else
		{

		}

		session.reset();
	}
	catch (Poco::Net::NetException & ex) 
	{
		errmsg = ex.displayText();
	}
	catch (std::exception& exc) 
	{
		errmsg = exc.what();
	}
	catch (...) {

	}

	if (!ret)
	{
		LOG_ERROR("WebAPI {} error, status = {}, errmsg = {}", strUrl, status, errmsg);
	}
	LOG_INFO("END {}", api);

	return ret;
}

bookmark_borderC++日期时间函数

获取毫秒时间戳

int64_t GetMilliSecond()
{
    return ::chrono::duration_cast<chrono::milliseconds>(chrono::system_clock::now().time_since_epoch()).count();
}

获取秒级时间戳

int32_t GetSecond()
{
	return ::chrono::duration_cast<chrono::seconds>(chrono::system_clock::now().time_since_epoch()).count();
}

获取秒级时间戳(根据给定的年、月、日、时、分、秒)

int32_t GetSecond(int year, int month, int day, int hour, int minute, int second)
{
	tm tm_;                                    // 定义tm结构体。
	tm_.tm_year = year - 1900;                 // 年,由于tm结构体存储的是从1900年开始的时间,所以tm_year为int临时变量减去1900。
	tm_.tm_mon = month - 1;                   // 月,由于tm结构体的月份存储范围为0-11,所以tm_mon为int临时变量减去1。
	tm_.tm_mday = day;                      // 日。
	tm_.tm_hour = hour;                      // 时。
	tm_.tm_min = minute;                     // 分。
	tm_.tm_sec = second;                     // 秒。
	tm_.tm_isdst = 0;                       // 非夏令时。
	time_t t_ = mktime(&tm_);                  // 将tm结构体转换成time_t格式。
	return t_;                            
}

bookmark_border小巧易用的c++格式化库fmtlib介绍

在标准C++中常常觉得拼接字符串是一件比较麻烦的事情,sscanf/sprintf系列函数可能我们大家用的最多的, 从第一次使用fmtlib库后,就发现这个东西实在是太方便了。

下载及使用方法

可以从https://github.com/fmtlib/fmt 下载源码,不需要编译,只需要包含对应的头文件即可。

使用起来非常方便,通过几个示例来看一下:

std::string tempstr = "world";
fmt::print("{}, {}!", "Hello", tempstr);
// 十六进制表示
std::string tempstr = fmt::format("{:x}", 80);
//The date is 2018-10-09.
std::time_t t = std::time(nullptr);fmt::print("The date is {:%Y-%m-%d}.\n", *std::localtime(&t));
//tempstr =="abracadabra"
std::string tempstr = fmt::format("{0}{1}{0}", "abra", "cad");

使用了fmtlib的相关项目

bookmark_borderWindows下UTF-8与GBK相互转换


dsdafdadadf

UTF-8转GBK:

std::string UTF8ToGBK(const std::string& utf8_string)
{
	int len = MultiByteToWideChar(CP_UTF8, 0, utf8_string.c_str(), -1, NULL, 0);
	std::wstring unicode_string(len, L'\0');
	MultiByteToWideChar(CP_UTF8, 0, utf8_string.c_str(), -1, &unicode_string[0], len);

	len = WideCharToMultiByte(CP_ACP, 0, &unicode_string[0], -1, NULL, 0, NULL, NULL);
	std::string gbk_string(len, '\0');
	WideCharToMultiByte(CP_ACP, 0, &unicode_string[0], -1, &gbk_string[0], len, NULL, NULL);

	return gbk_string;
}

GBK转UTF-8:

std::string GBKToUTF8(const std::string& gbk_string)
{
	int len = MultiByteToWideChar(CP_ACP, 0, gbk_string.c_str(), (int)gbk_string.size(), NULL, 0);
	std::wstring unicode_string(len, L'\0');
	MultiByteToWideChar(CP_ACP, 0, gbk_string.c_str(), (int)gbk_string.size(), &unicode_string[0], len);

	len = WideCharToMultiByte(CP_UTF8, 0, &unicode_string[0], (int)unicode_string.size(), NULL, 0, NULL, NULL);
	std::string utf8_string(len, u8'\0');
	WideCharToMultiByte(CP_UTF8, 0, &unicode_string[0], (int)unicode_string.size(), &utf8_string[0], len, NULL, NULL);

	return utf8_string;
}

bookmark_borderrapidjson库示例及函数封装

开发工作中涉及JSON文件的解析/编码是不可避免的,象PHP/JAVA/C#等语言中都内置有非常方便的JSON操作类库,但C++自身没有提供这样的操作方法,因此不得不借助一些第三方库来完成JSON操作。之前使用过jsoncpp,感觉不是太好,对于一些含有特殊字符的json内容解析时还可能发生程序崩溃,后来接触到RadpidJSON,发现非常不错,据官方宣称是最快的JSON库,所以称之为"RAPID"。

下面是本人在工作中封装的工具函数,使用非常方便,能够满足大多数情况下JSON操作的需要,能够大节省我们的编码时间。

struct TStrMapVec
{
    vector<map<string, string>> vec_;
};

struct TJsonParseResult
{
public:
    bool FindParam(const std::string& key)
    {
        std::string name(key);
        std::transform(name.begin(), name.end(), name.begin(), ::tolower);

        auto it = m_mapParams.find(name);
        if (it != m_mapParams.end())
        {
            return true;
        }

        auto it1 = m_mapArray.find(name);
        if (it1 != m_mapArray.end())
        {
            return true;
        }

        return false;
    }

    std::string GetParam(const std::string& key)
    {
        std::string name(key);
        std::transform(name.begin(), name.end(), name.begin(), ::tolower);

        std::string value;
        auto it = m_mapParams.find(name);
        if (it != m_mapParams.end())
        {
            value = it->second;
        }
        return value;
    }

    void GetArrayParam(const std::string& key, std::vector<std::map<std::string, std::string>>& vecParams)
    {
        std::string name(key);
        std::transform(name.begin(), name.end(), name.begin(), ::tolower);

        auto it = m_mapArray.find(name);
        if (it != m_mapArray.end())
        {
            vecParams = it->second.vec_;
        }
    }

    void AddParam(const std::string& key, const std::string& value)
    {
        std::string name(key);
        std::transform(name.begin(), name.end(), name.begin(), ::tolower);
        m_mapParams[name] = value;
    }

    void AddArrayParam(const std::string& key, std::map<std::string, std::string>& mapParams)
    {
        std::string name(key);
        std::transform(name.begin(), name.end(), name.begin(), ::tolower);
        m_mapArray[name].vec_.push_back(mapParams);
    }

    void RemoveParam(std::string name)
    {
        m_mapParams.erase(name);
        m_mapArray.erase(name);
    }

    bool IsEmpty()
    {
        return m_mapParams.empty() && m_mapArray.empty();
    }

public:
    map<string, string> m_mapParams;    
    map<string, TStrMapVec> m_mapArray;
};

static void ParseJsonObj(const rapidjson::Value& jsonObj, TJsonParseResult& zjapiRes, string namePrefix = "")
{
    if (jsonObj.IsNull()
        || jsonObj.IsObject() == false)
    {
        return;
    }

    for (auto it = jsonObj.MemberBegin(); it != jsonObj.MemberEnd(); ++it)
    {
        auto key = it->name.GetString();
        const rapidjson::Value& jsonValue = it->value;
        string name = namePrefix;
        string value;

        if (name.empty() == false)
        {
            name += ".";
        }
        name += key;

        if (jsonValue.IsString()
            || jsonValue.IsNumber())
        {
            if (jsonValue.IsString())
            {
                value = jsonValue.GetString();
            }
            else if (jsonValue.IsInt())
            {
                value = to_string(jsonValue.GetInt());
            }
            else if (jsonValue.IsUint())
            {
                value = to_string(jsonValue.GetUint());
            }
            else if (jsonValue.IsInt64())
            {
                value = to_string(jsonValue.GetInt64());
            }
            else if (jsonValue.IsUint64())
            {
                value = to_string(jsonValue.GetUint64());
            }
            else if (jsonValue.IsDouble())
            {
                value = to_string(jsonValue.GetDouble());
            }

            zjapiRes.AddParam(name, value);
        }
        else if (jsonValue.IsArray())
        {
            //假定为数组时,数组元素只能是类似于{"a":1,"b":2}这样不再包含子数组
            map<string, string> mapParams;
            for (size_t i = 0; i < jsonValue.Size(); i++)
            {
                const rapidjson::Value& arrItem = jsonValue[i];
                if (arrItem.IsNull()
                    || arrItem.IsObject() == false)
                {
                    continue;
                }

                auto jsonText = std::move(JsonToString(arrItem));
                mapParams["json"] = jsonText;

                for (auto itItemMember = arrItem.MemberBegin(); itItemMember != arrItem.MemberEnd(); ++itItemMember)
                {
                    auto itemMemberKey = itItemMember->name.GetString();
                    const rapidjson::Value& jsonItemMemberValue = itItemMember->value;

                    if (jsonItemMemberValue.IsString())
                    {
                        mapParams[itemMemberKey] = jsonItemMemberValue.GetString();
                    }
                    else if (jsonItemMemberValue.IsInt())
                    {
                        mapParams[itemMemberKey] = to_string(jsonItemMemberValue.GetInt());
                    }
                    else if (jsonItemMemberValue.IsUint())
                    {
                        mapParams[itemMemberKey] = to_string(jsonItemMemberValue.GetUint());
                    }
                    else if (jsonItemMemberValue.IsInt64())
                    {
                        mapParams[itemMemberKey] = to_string(jsonItemMemberValue.GetInt64());
                    }
                    else if (jsonItemMemberValue.IsUint64())
                    {
                        mapParams[itemMemberKey] = to_string(jsonItemMemberValue.GetUint64());
                    }
                    else if (jsonItemMemberValue.IsArray())
                    {
                        mapParams[itemMemberKey] = std::move(JsonToString(jsonItemMemberValue));
                    }
                }

                zjapiRes.AddArrayParam(name, mapParams);
            }
        }
        else if (jsonValue.IsObject())
        {
            ParseJsonObj(jsonValue, zjapiRes, name);
        }
    }
}

//JSON解析工具函数
void ParseJson(const std::string& jsonRes, TJsonParseResult& jsonparseresult)
{
    rapidjson::Document jsonDoc;
    jsonDoc.Parse<0>(jsonRes.c_str());
    if (jsonDoc.HasParseError())
    {
        rapidjson::ParseErrorCode code = jsonDoc.GetParseError();
        return;
    }

    ParseJsonObj(jsonDoc, jsonparseresult);
}

比如对于json内容{"a":1,"b":2},调用ParseJson后,输出参数jsonparseresult的map中存在2个元素:
"a" => 1, "b" => 2

bookmark_borderPoco C++库简介 (转)

学习一个框架前,要先明白它的是什么,为什么,怎么用.下面这些文字,是从中文poco官网上转过来的,正如poco c++库的特点,非常清晰,代码风格更是一目了然.

   poco开发库的特点,非常适合写后台处理程序,效率也是很高的.前台界面程序使用Qt框架库,非常好,两个库相辅相成,可解决项目上的大部分问题.

注:更多详情可以访问Poco官方网站:https://pocoproject.org

Poco C++库是:

  • 一系列C++类库,类似Java类库,.Net框架,Apple的Cocoa;

  • 侧重于互联网时代的网络应用程序

  • 使用高效的,现代的标准ANSI/ISO C++,并基于STL

  • 高可移值性,并可在多个平台下可用

  • 开源,并使用Boost Software License发布

  • 不管是否商用,都完全免费

特性:

  • DynamicAny与Any类

  • Cache框架

  • 基于OpenSSL的密码系统

  • 日期,时间类库

  • 事件和通知框架

  • FTP客户端

  • 跨平台的文件系统类库

  • HTML表单类库

  • HTTP客户端和服务端(支持SSL),C++ 服务器页面编译器

  • 日志框架

  • 多线程框架(线程池,活动对象,工作队列等)

  • POP3客户端类库

  • 跨平台,一次编写,多平台编译和运行

  • 进程管理和进程间通信类库

  • 反射框架

  • 基于PCRE的正则表达式

  • SMTP客户端类库

  • 数据库访问类库(SQLite,MySQL, ODBC)

  • 支持SSL/TLS,基于OpenSSL

  • 动态类库加载

  • 先进的内存和指针管理(Buffer, Pool)

  • Socket类库

  • 网络数据流类库,支持Base64,HexBinary编解码,压缩等等

  • 字符串格式化和其它字符串工具类库

  • TCP服务器框架(多线程)

  • 文本编码和转换

  • Tuples

  • URI支持

  • 支持UTF8和Unicode编码

  • UUID生成器

  • XML生成和解析器

  • Zip文件操作类库

Poco的使命

  • Poco是一个强大的类库,并易于构建自己的应用程序

  • Poco帮助你创建跨平台的应用程序(一次编写,多平台编译和运行)

  • 模块化和可扩展,可应用于嵌入式到企业级程序

  • 提供全面,易懂的编程接口

  • 使用C++语言,快速且高效

  • Poco崇尚简易

  • 在设计,代码风格和文档上保持一致

  • Poco强调代码质量,包括可读性,综合性,一致性,编码风格和可测试性

  • Poco使得C++编程更加容易

指导方针

  • 高度关注代码质量,编码风格,一致性,可读性

  • 高度关注测试

  • 注重实用性

  • 基于现有的,可靠的组件开发

版本历史

  • Summer 2004: Günter Obiltschnig started development

  • February 2005: First release on SourceForge

  • (Release 0.91 under Sleepycat license)

  • May 2005: First contributions by Aleksandar Fabijanic

  • January 2006: Release 1.0

  • March 2006: Release 1.1

  • July 2006: Moved to Boost license, POCO Community Website

  • August 2006: Release 1.2

  • May 2007: Release 1.3

  • July 2010: Stable Release 1.3.7,

  • about 20 contributors, used in 100s of projects

支持平台

  • Microsoft Windows

  • Linux

  • Mac OS X

  • HP-UX, Solaris, AIX*

  • Embedded Linux (uClibc, glibc)

  • iOS

  • Windows Embedded CE

  • QNX

Poco应用场景

  • 创建自动化的中间件和设备

  • 工业自动化和工业设备

  • 流量控制系统

  • 健康系统

  • 测量,数据收集和测试系统

  • 消费电子产品和家庭自动化产品

  • 测量

  • 航空交通管理系统

  • VoIP

  • 票务和入口控制系统

  • 包装应用程序

Poco的优势

  • 全面的,完整的C++框架,可减少开发工作,快速让产品走向市场

  • 易学易使用,以及相当多的示例代码和良好的文档

  • 原生的C++代码,性能优秀,低内存占用

  • 平台无关,一处编写,跨平台编译和运行

    • 大多数情况下,可以开发机上完成开发和调试工作

    • 可以非常容易的迁移到新平台

       

 

设计 & 实现

   基于现代的、标准的ANSI C++编写,使用C++ STL库。模块化设计,极少的外部依赖,易于编译和使用。结合传统的面向对象与现代的C++设计,代码易读,代码风格统一,以及相当全面的测试用例。

支持平台

  • 桌面/服务器: Windows, Linux, Mac OS X, Solaris, HP-UX, AIX

  • 嵌入式系统: Windows Embedded CE, Embedded Linux (uClibc or glibc), iOS, QNX, VxWorks, Android

  • 最低系统要求: 75 MHz ARM9, 8 MB RAM (Embedded Linux).

License

  • Boost Software License 1.0

核心特性

  • 支持Any 和 DynamicAny 的动态类型

  • 提供缓存框架

  • 日期和时间

  • 事件与通知框架

  • (libPoco.com翻译,转载请注明)

  • 基于PCRE的正则表达式

  • 动态库加载

  • 完美的指针和内存管理 (buffer, pool)

  • 字符串格式化和工具

  • tuples

压缩

  • 基于zlib的压缩/解压类

  • 创建和解压ZIP文件

加密

  • 支持多种hash算法

  • 支持X509数字证书

  • 对称的和 RSA算法

  • 支持streams加解密

  • 基于OpenSSL

数据库

  • 不同的数据库提供了统一的访问接口(SQLite, MySQL, ODBC)

  • 自动数据类型匹配

  • 支持集合类 (std::vector, std::set, std::map, etc.)

  • 支持记录集和tuples

  • 支持连接池

文件系统

  • 跨平台的文件路径操作

  • 目录列表

  • 通配符支持

  • 文件属性管理

日志

  • 可扩展的日志框架,可拔插的日志通道和消息格式化

  • 日志可输出到终端,日志文件,syslog,远程syslog,Windows事件服务

多线程

  • 线程和线程同步类库

  • 线程池

  • 工作队列

  • 活动对象

  • 任务管理

  • 定时器

网络

  • 流,数据报,多播,服务器和原生socket.

  • TCP服务器框架(多线程)

  • 反射服务器框架

  • HTTP(S)客户和服务器框架

  • HTTP认证

  • CSP(C++ Server Page)编译器

  • FTP客户端

  • SMTP和POP3客户端

  • (libPoco.com翻译,转载请注明)

  • 支持URI, UUID

  • HTML表单处理

  • MIME支持

  • 基于 OpenSSL支持SSL/TLS

  • WebSocket (RFC 6455) 客户和服务器

进程管理和 IPC

  • 进程启停

  • 进程间同步

  • 共享内存

  • Base64 和 HexBinary 编解码

  • 压缩(zlib)

  • 行结束符车换

  • 内存stream

  • 文本编码转换

  • URI流读取

文本编码

  • 支持UTF-8 和 Unicode

  • 文本编码和转换

  • 字符分类

工具类

  • 支持命令行和服务器程序框架

  • 命令行参数解析器

  • 配置文件解析

  • 支持Unix和Windows后台服务

XML

  • 基于 Expat 的XML解析

  • SAX2 (Simple API for XML, version 2) 解析器

  • DOM (Document Object Model, Level 1-3) 解析器

  • XML生成器

bookmark_borderVC开发DLL工程在什么情况下只生成DLL,不生成LIB

DLL程序中必须导出至少一个函数/变量/类。
没有导出的话就不生成LIB。


如果LIB是静态库则不需要DLL 。
如果LIB是动态链接的,那么就必须找到DLL 。
动态链接时,LIB只包含简单的DLL导出定义和辅助链接,并不包含可执行实体。


动态链接与静态链接的不同之处在于:
动态链接允许可执行模块(.dll 文件或 .exe 文件)仅包含在运行时定位 DLL 函数的可执行代码所需的信息。
在静态链接中,链接器从静态链接库获取所有被引用的函数,并将库同代码一起放到可执行文件中。


lib后缀的库文件有两种:
一种为静态链接库(Static Libary,简称"静态库");
另一种为动态连接库的导入库(Import Libary,简称"导入库")。