C++:偏移类型

地址偏移类型在C艹中算是偏冷门的技术,但在特定场合下可以节省大量的代码从而实现需求。这种类型的定义为:类或结构体中的数据成员相对于基址的偏移量。比如,一个类里面成员a地址相对于类基地址偏移量为4;成员b地址相对于类基地址偏移量为8等等。
示例代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;
 
class A {
public:
    int a, b, c;
    A () : a (3), b (5), c (7) {}
};
 
int main (int argc, char* argv[]) {
    int (A::* x) = &A::a;
    int A::* y = &A::b;
    using TZ = int (A::*);
    TZ z = &A::c;    
 
    A *p = (A*)nullptr;
 
    cout << "地址偏移与偏移量值:" << endl;
    cout << &(p->a) << '\t' << &(p->*x) << endl;
    cout << &(p->b) << '\t' << &(p->*y) << endl;
    cout << &(p->c) << '\t' << &(p->*z) << endl;
 
    cout << "直接访问的结果:" << endl;
    cout << x << '\t' << y << '\t' << z << endl;
 
    return 0;
}

代码含义为:首先创建一个类,类里面有三个int类型成员属性,然后在main函数里面写了三种生成地址偏移类型的方法,其中第三种为首先构造地址偏移类型,然后用类型来定义。从经验上看,很容易看出偏移类型为0、4、8,实际运行结果也确实如此。
本机运行结果如下:
20160910151508
直接访问的结果有点出人意料,按道理说也应该是0、4、8才对,难道只代表一个符号么?
于是,在Disassembly上调试,为便于查看,我将代码改为cout << x;,以上代码反汇编结果为:
20160910152858
通过断点调试,x、y、z的值确实是0、4、8,另外反汇编代码可以明显看出,直接打印的含义为,如果值为0xFFFFFFFF,那么显示0,否则为1。因为通常不需要直接打印偏移长度,所以就把这个功能给省略了。真正需要用到的是,这个偏移是不是有效的。定义为,假如偏移长度为0xFFFFFFFF,那么代表这个偏移是无效的。于是我简单加了个hack:

1
2
__asm { mov x, 0ffffffffh }
cout << x;

代码不出所料,结果为0。这儿的0和1分别代表此处偏移类型是否有效。

C++:如何制作高逼格二维码

在网上看到一个制作高逼格二维码的文章,来源http://www.chenxublog.com/2016/05/22/pic-qrcode-colorful.html
步骤那可是相当的复杂,一堆软件各种ps啊什么的,不过根据实现的效果一看,原理貌似很简单嘛,何必弄那么复杂,于是我用代码实现了一个,本文着重介绍原理。编译后的程序在最下面,不过建议使用前先看过去,否则可能你不会用2333
先来几张图你们感受下,支付宝:
zfb

微信:
wx
继续阅读C++:如何制作高逼格二维码

C++:socket服务端模型

首先解释下socket含义。网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket。 Socket的英文原义是“孔”或“插座”。作为BSD UNIX的进程通信机制,取后一种意思。通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。
下面我列举几个常用的服务端TCP socket实现代码

1、首先是最原始的阻塞模型。这种模型简单易懂,[以下代码基于Windows]:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <winsock2 .h>
#pragma comment(lib, "ws2_32.lib")
 
int mian (int argc, char* argv []) {
    //Winsock环境初始化
    WSAData wd;
    WSAStartup (MAKEWORD (2, 2), &wd);
 
    //创建套接字
    SOCKET sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);//对于UDP协议,第二个参数填 SOCK_DGRAM
 
    //绑定前的操作,UDP可以不用绑定
    sockaddr_in addr;
    addr.sin_family = AF_INET;//需要绑定的本地地址
    addr.sin_addr.s_addr = 0;
    addr.sin_port = htons (51423);//需要绑定的本地端口
 
    //执行绑定
    bind (sock, (struct sockaddr*)&addr, sizeof (addr));
 
    //监听
    listen (sock, SOMAXCONN);
 
    while (true) {
        //如果有链接请求,则接受链接
        SOCKET session = accept (sock, NULL, NULL);
        if (INVALID_SOCKET == session) break;
 
        //接收数据
        char buf [1024];
        int len = recv (session, buf, sizeof (buf), 0);
 
        //发送数据
        send (session, buf, len, 0);
 
        //关闭链接
        closesocket (session);
    }
 
    //关闭套接字
    closesocket (sock);
 
    //Winsock环境释放
    WSACleanup ();
    return 0;
}</winsock2>

继续阅读C++:socket服务端模型

C++:文件操作

文件操作是个啥大家都懂了,下面我给出几个文件操作示例
1、C语言文件操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//在windows平台下避免函数不安全报错而定义的一个宏
#define _CRT_SECURE_NO_WARNINGS
#include <stdio .h>
#include <stdlib .h>
#include <string .h>
 
int main () {
    //fopen第二个参数有以下几种取值模式
    //首先是打开方式,从以下打开方式中任选一种或组合
    //    a(append)    以写方式打开文件并移动文件指针到文件尾部
    //    r(read)      以读方式打开文件,文件指针位置未知建议打开后重置文件指针
    //    w(write)     以写方式打开文件并清空文件内容
    //然后是数据类型,默认为文本方式,如果加上b则为二进制方式,区别在于,在windows环境下,不加b(文本模式)会造成:
    //    以文本方式读文件时,换行符\r\n被读成\n
    //    以文本方式写文件时,换行符\n被写成\r\n
    //最后是扩展方式,如果带+号代表如果文件不存在则新建。但我实际测试结果为,带不带+号并没什么卵用
    //示例:第二个参数为 rwb+ 代表以二进制读写方式打开文件,如果文件不存在则新建
    FILE *f = fopen ("a.txt", "rw+");
    if (f) {
        char *data = "hello";
        //写文件,不多做解释
        fwrite (data, strlen(data), 1, f);
 
        //移动文件指针到结束位置,第三个参数三种取值分别为 SEEK_SET(开始位置)、SEEK_CUR(当前位置)、SEEK_END(结束位置)
        fseek (f, 0, SEEK_END);
 
        //获取文件指针的偏移,这时候指针在末尾,含义就代表文件长度。
        //值得注意的是如果以文本方式并且有回车并且读取文件时,文件长度与读取的字节数不一样,原因上面有说明
        int len = ftell (f);
 
        //这行代码含义为移动文件指针到文件起始位置,等价于 fseek (f, 0, SEEK_SET);
        rewind (f);
 
        //其他文件操作函数不做说明,这儿给出常用列表
        //fwrite     输出一块数据到文件
        //fprintf    格式化输出到文件
        //fputc      输出一个字节到文件
        //fputs      输出一串字符串到文件
        //fread      读取一块数据到文件
        //fscanf     从文件格式化输入
        //fgetc      从文件中读取一个字符,因为文件可能结束,所以返回类型为int。如果值为 EOF 代表文件已读到最后
        //fgets      从文件中读取一串字符串
        //feof       判断文件指针是否在文件末尾
 
        //如果为多个程序同时访问文件的情况时建议加上这句。含义代表将文件缓冲区内容刷新到文件中
        //不加可能出现文件更新不及时的现象,不管是否调用这句,关闭文件时始终会刷新的
        fflush (f);
 
        //关闭文件
        fclose (f);
    } else {
        printf ("打开文件失败!");
    }
 
    system ("pause");
    return 0;
}</string></stdlib></stdio>

继续阅读C++:文件操作

Windows服务访问控制

服务控制在win32用户层系统编程中比较重要,一般用于创建自启动项或加载驱动,这样的话启动服务就是载入驱动,停止服务就是卸载驱动,极大方便了驱动控制。下面贴一个服务控制代码,可用于方便的控制服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#pragma once
#ifndef __HSERVER_HPP__
#define __HSERVER_HPP__
 
#include <Windows.h>
 
class hService {
    SC_HANDLE h_scm = NULL, h_service = NULL;
    QUERY_SERVICE_CONFIG *h_qsc = NULL;
    SERVICE_STATUS h_status;
 
public:
    hService (LPCTSTR serv_name) {
        h_qsc = (LPQUERY_SERVICE_CONFIG)new BYTE [8 * 1024];
        if ((h_scm = ::OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS)) && serv_name && serv_name[0]) {
            h_service = ::OpenService (h_scm, serv_name, SERVICE_ALL_ACCESS);
        }
    }
    ~hService () {
        delete h_qsc;
        if (h_service) ::CloseServiceHandle (h_service);
        if (h_scm) ::CloseServiceHandle (h_scm);
    }
 
    //服务是否正在运行
    BOOL is_running () {
        if (!h_service) return FALSE;
        if (::QueryServiceStatus (h_service, &h_status)) {
            if (h_status.dwCurrentState == SERVICE_RUNNING) return TRUE;
        }
        return FALSE;
    }
 
    //服务是否已停止
    BOOL is_stopped () {
        if (!h_service) return FALSE;
        if (::QueryServiceStatus (h_service, &h_status)) {
            if (h_status.dwCurrentState == SERVICE_STOPPED) return TRUE;
        }
        return FALSE;
    }
 
    //服务是否已暂停
    BOOL is_pause () {
        if (!h_service) return FALSE;
        if (::QueryServiceStatus (h_service, &h_status)) {
            if (h_status.dwCurrentState == SERVICE_PAUSED) return TRUE;
        }
        return FALSE;
    }
 
    //服务是否自动启动
    BOOL is_auto_run () {
        DWORD d;
        if (!h_service) return FALSE;
        if (::QueryServiceConfig (h_service, h_qsc, 8 * 1024, &d)) {
            return h_qsc->dwStartType <= 2;
        }
        return FALSE;
    }
 
    //启动服务
    BOOL start () {
        if (!h_service) return FALSE;
        if (is_running ()) return TRUE;
        return ::StartService (h_service, NULL, NULL);
    }
 
    //停止服务
    BOOL stop () {
        if (!h_service) return FALSE;
        if (is_stopped ()) return TRUE;
        return ::ControlService (h_service, SERVICE_CONTROL_STOP, &h_status);
    }
 
    //暂停服务
    BOOL pause () {
        if (!h_service) return FALSE;
        if (is_running ()) return ::ControlService (h_service, SERVICE_CONTROL_PAUSE, &h_status);
        return TRUE;
    }
 
    //恢复服务
    BOOL resume () {
        if (!h_service) return FALSE;
        if (is_pause ()) return ::ControlService (h_service, SERVICE_CONTROL_CONTINUE, &h_status);
        return is_running ();
    }
 
    //设置自动启动服务
    BOOL auto_start () {
        if (!h_service) return FALSE;
        if (is_auto_run ()) return TRUE;
        SC_LOCK sclLock = ::LockServiceDatabase (h_scm);
        BOOL bRet = ::ChangeServiceConfig (h_service, SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
        if (sclLock) ::UnlockServiceDatabase (sclLock);
        return bRet;
    }
 
    //设置手动启动服务
    BOOL demand_start () {
        if (!h_service) return FALSE;
        if (!is_auto_run ()) return TRUE;
        SC_LOCK sclLock = ::LockServiceDatabase (h_scm);
        BOOL bRet = ::ChangeServiceConfig (h_service, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_NO_CHANGE, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
        if (sclLock) ::UnlockServiceDatabase (sclLock);
        return bRet;
    }
 
    //创建服务
    static hService *create_service (LPCTSTR serv_name, LPCTSTR display_name, DWORD service_type, LPCTSTR path) {
        hService *service = new hService (NULL);
        service->h_service = ::CreateService (service->h_scm, serv_name, display_name, SC_MANAGER_ALL_ACCESS, service_type, SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, path, NULL, NULL, NULL, NULL, NULL);
        return service;
    }
 
    //删除服务
    BOOL delete_service () {
        if (::DeleteService (h_service)) {
            h_service = NULL;
            return TRUE;
        }
        return FALSE;
    }
};
#endif //__HSERVER_HPP__

创建头文件,引入以上代码之后,就可以方便进行服务控制了。调用方式在代码中已有注释。

Windows下编码转换

对于网络程序来说经常需要用到编码转换,比如访问utf8编码网页下载之后,转为unicode进行显示。windows自带的编码API比较难用,所以对其进行简单的封装。分SDK和MFC两个版本代码,SDK版本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#pragma once
#ifndef __HCODEC_HPP__
#define __HCODEC_HPP__
 
#include <windows .h>
#include <string>
 
class hCodec {
    //不可实例化
    hCodec () = delete;
    ~hCodec () = delete;
 
    static bool hCodec::_conv_Down (std::wstring& _old, std::string& _new, UINT ToType) {
        int lenOld = lstrlenW (_old.c_str ());
        int lenNew = ::WideCharToMultiByte (ToType, 0, _old.c_str (), lenOld, NULL, 0, NULL, NULL);
        std::string s;
        s.resize (lenNew);
        bool bRet = ::WideCharToMultiByte (ToType, 0, _old.c_str (), lenOld, const_cast<char *>(s.c_str ()), lenNew, NULL, NULL);
        _new.clear ();
        _new = s.c_str ();
        return bRet;
    }
    static bool hCodec::_conv_Up (std::string& _old, std::wstring& _new, UINT ToType) {
        int lenOld = lstrlenA (_old.c_str ());
        int lenNew = ::MultiByteToWideChar (ToType, 0, _old.c_str (), lenOld, NULL, 0);
        std::wstring s;
        s.resize (lenNew);
        bool bRet = ::MultiByteToWideChar (ToType, 0, _old.c_str (), lenOld, const_cast<wchar_t *>(s.c_str ()), lenNew);
        _new.clear ();
        _new = s.c_str ();
        return bRet;
    }
 
public:
    static bool hCodec::AnsiToUnicode (std::string& _old, std::wstring& _new) {
        return hCodec::_conv_Up (_old, _new, CP_ACP);
    }
    static bool hCodec::UnicodeToAnsi (std::wstring& _old, std::string& _new) {
        return hCodec::_conv_Down (_old, _new, CP_ACP);
    }
    static bool hCodec::Utf8ToUnicode (std::string& _old, std::wstring& _new) {
        return hCodec::_conv_Up (_old, _new, CP_UTF8);
    }
    static bool hCodec::UnicodeToUtf8 (std::wstring& _old, std::string& _new) {
        return hCodec::_conv_Down (_old, _new, CP_UTF8);
    }
    static bool hCodec::AnsiToUtf8 (std::string& _old, std::string& _new) {
        std::wstring t;
        if (!hCodec::AnsiToUnicode (_old, t)) return false;
        return hCodec::UnicodeToUtf8 (t, _new);
    }
    static bool hCodec::Utf8ToAnsi (std::string& _old, std::string& _new) {
        std::wstring t;
        if (!hCodec::Utf8ToUnicode (_old, t)) return false;
        return hCodec::UnicodeToAnsi (t, _new);
    }
};
 
#endif //__HCODEC_HPP__</wchar_t></char></string></windows>

继续阅读Windows下编码转换

Windows注册表访问的封装

注册表这东西用的越来越少了,但在特定场合还是不可替代的东西。比如开机启动项、环境变量和文件扩展名等各种系统信息都是放在注册表中。
由于注册表API访问稍微麻烦了点,于是我对其进行简单的封装。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#pragma once
#ifndef __HREG_HPP__
#define __HREG_HPP__
 
#include <Windows.h>
 
// main_key 注册表根键可取值
// HKEY_CLASSES_ROOT
// HKEY_CURRENT_CONFIG
// HKEY_CURRENT_USER
// HKEY_LOCAL_MACHINE
// HKEY_USERS
 
// type 键值类型可取值
// REG_BINARY               二进制数据
// REG_DWORD                双字
// REG_DWORD_LITTLE_ENDIAN  双字小头模式
// REG_DWORD_BIG_ENDIAN     双字大头模式
// REG_EXPAND_SZ            包含未展开的环境变量的引用的字串
// REG_LINK                 一个用 RegCreateKeyEx 传 REG_OPTION_CREATE_LINK 创建的符号链接的字串
// REG_MULTI_SZ             多个字符串,用\0分隔,末尾为\0\0
// REG_NONE                 没定义值类型
// REG_QWORD                四字
// REG_QWORD_LITTLE_ENDIAN  四字小头模式
// REG_SZ                   普通字符串
 
 
class hReg {
    //不可实例化
    hReg () = delete;
    ~hReg () = delete;
    hReg (hReg&) = delete;
 
public:
    //创建注册表路径
    //main_key:   注册表根键
    //sub_key:    注册表路径
    //type:       键值类型
    //value:      值
    //value_size: 值长度(字节)
    static BOOL set_path (HKEY main_key, LPCTSTR sub_key, DWORD type, LPBYTE value, DWORD value_size) {
        return ERROR_SUCCESS == ::RegSetValueEx (main_key, sub_key, 0, type, value, value_size);
    }
 
    //创建注册表键值
    //main_key:   注册表根键
    //sub_key:    注册表路径
    //sub_key2:   键值名称
    //type:       键值类型
    //value:      值
    //value_size: 值长度(字节)
    static BOOL set_key (HKEY main_key, LPCTSTR sub_key, LPCTSTR sub_key2, DWORD type, LPBYTE value, DWORD value_size) {
        HKEY hKey;
        if (ERROR_SUCCESS != ::RegOpenKeyEx (main_key, sub_key, 0, KEY_WRITE, &hKey)) return FALSE;
        BOOL bRet = ERROR_SUCCESS == ::RegSetValueEx (hKey, sub_key2, 0, type, value, value_size);
        ::RegCloseKey (hKey);
        return bRet;
    }
 
    //获取注册表路径键值
    //main_key:   注册表根键
    //sub_key:    注册表路径
    //value:      值
    //value_size: 值长度(字节)
    static BOOL get_path_value (HKEY main_key, LPCTSTR sub_key, LPBYTE value, DWORD &value_size) {
        return ERROR_SUCCESS == ::RegQueryValueEx (main_key, sub_key, NULL, NULL, value, &value_size);
    }
 
    //获取注册表路径键值
    //main_key:   注册表根键
    //sub_key:    注册表路径
    //sub_key2:   键值名称
    //value:      值
    //value_size: 值长度(字节)
    static BOOL get_key_value (HKEY main_key, LPCTSTR sub_key, LPCTSTR sub_key2, LPBYTE value, DWORD &value_size) {
        HKEY hKey;
        if (ERROR_SUCCESS != ::RegOpenKeyEx (main_key, sub_key, 0, KEY_READ, &hKey)) return FALSE;
        BOOL bRet = ERROR_SUCCESS == ::RegQueryValueEx (hKey, sub_key2, NULL, NULL, value, &value_size);
        ::RegCloseKey (hKey);
        return bRet;
    }
 
    //删除注册表路径
    //main_key:   注册表根键
    //sub_key:    注册表路径
    static BOOL delete_path (HKEY main_key, LPCTSTR sub_key) {
        return ERROR_SUCCESS == ::RegDeleteKey (main_key, sub_key);
    }
 
    //删除注册表键值
    //main_key:   注册表根键
    //sub_key:    注册表路径
    //sub_key2:   注册表路径
    static BOOL delete_key (HKEY main_key, LPCTSTR sub_key, LPCTSTR sub_key2) {
        HKEY hKey;
        if (ERROR_SUCCESS != ::RegOpenKeyEx (main_key, sub_key, 0, KEY_ALL_ACCESS, &hKey)) return FALSE;
        BOOL bRet = ERROR_SUCCESS == ::RegDeleteKey (hKey, sub_key2);
        ::RegCloseKey (hKey);
        return bRet;
    }
};
 
#endif //__HREG_HPP__

全部为静态函数,注上了比较完整的注释,另外函数名也较之前清晰,统一返回BOOL表示执行成功或失败。

C++机器学习(4)Logistic回归

部分资料下载地址: http://pan.baidu.com/s/1bpsgt5t 提取码fwxf
源码下载地址:https://github.com/fawdlstty/hm_ML

继续开始机器学习的研究。这次的内容叫Logistic回归。什么叫Logistic回归?直观理解就是,通过不断的迭代,使结果接近最优解。
如下图示例:
20160517120948
在由θ0、θ1以及J(θ0,θ1)组成的三维立体空间中,从最开始的山顶上,每走一步计算一下怎样走下山最快。通过不同的起点或不同的步长,甚至可以获得不同的结果,比如红色箭头所标注的位置。
继续阅读C++机器学习(4)Logistic回归

网站https加密访问实现

20160508201012
https加密访问有好处也有坏处,好处主要有别人无法嗅探到通讯内容,网址的绿锁图标也代表安全,坏处也有比如消耗服务器端资源,另外也无法提供适用的cdn加速,主要看个人取舍。证书主要有两种,主要面向个人用户与企业用户。个人型证书一般可以免费申领,主要效果是网址前面有绿锁图标,企业型证书需要购买,可以在网址前面显示公司名称等。
免费SSL证书可以在 沃通StarSSLLet's Encrypt 上获得,其中沃通和StarSSL是申请,Let's Encrypt是在服务器上安装指定软件,验证之后生成证书。
继续阅读网站https加密访问实现

C++:STL迭代

STL中的迭代是个重点,里面提供了大量的方法来方便我们程序猿开发,不过由于提供的太多导致学习比较吃力。这儿记录部分学习过程。
首先是C++11的for循环,比如对于一个vector v,可以通过for(int i : v)来实现迭代。如果对于自定义结构呢?也可以实现,如下代码示例调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
#include <vector>
#include <string>
using namespace std;
 
class Int_col {
public:
    Int_col () { for (int i = 0; i < 10; i++) data [i] = i; }
    int data [10];
    int* begin () { return &data [0]; }
    int* end () { return &data [10]; }
};
 
int main(int argc, char* argv[]) {
    Int_col v;
    for (int i : v) {
        cout << i << " ";
    }
 
    return 0;
}

这儿的结构中只有10个数据,在结构中提供begin与end方法的迭代器,即可实现C++11的for循环调用。结果如下所示:
20160502225605
继续阅读C++:STL迭代

网站服务器伪静态环境配置

伪静态是个好东西,可以用来SEO优化等,由于Wordpress+Nginx配置比较麻烦,免不了入一些坑,所以写个博文方便新晋站长们配置。
首先在Wordpress的“设置”-“固定链接”菜单中设置固定链接为自定义结构,我的是/archives/%post_id%.html这个,小站长们随意,注意Nginx配置时统一一下就阔以咯,然后分类目录前缀category,标签前缀tags,然后保存更改。
这时候你将会神奇的发现,整个网站就首页可以访问,其他都访问不了了。别慌,接下来配置Nginx。在location里面撸上如下代码:

1
2
3
4
5
6
7
8
location / {
    root   ...;
    index  index.html index.htm index.php;
    if (!-e $request_filename){
        rewrite ^/archives/(\d+)\.html$ /index.php?p=$1;
        rewrite ^/([^\.]+)$ /index.php?$1;
    }
}

root别照抄,其他根据自身环境修改。重点在于if,这关键字与括号间必须要有个空格。这几句话意思是,如果访问的文件不存在,那么,就看看是不是archives开头的,如果是就代表介个是文章,用正则将其替换为/?p=形式转发给index.php,然后剩余无法访问的伪路径直接转发给index.php,包括标签、分类目录、页面等。
配置完成后重启服务器/usr/local/nginx/sbin/nginx -s reload,然后,估计整个网站全部正常访问。这时候就代表伪静态配置成功

C++机器学习(3)朴素贝叶斯

部分资料下载地址: http://pan.baidu.com/s/1bpsgt5t 提取码fwxf
源码下载地址:https://github.com/fawdlstty/hm_ML

朴素贝叶斯这东西呢,主要用于文本相关处理,比如通过邮件内容判断是否是垃圾邮件等等。
具体实现思路是:比如判断某个邮件的内容是否是垃圾邮件,那么弄两个文本向量,分别代表正常邮件的关键字与垃圾邮件关键字,然后计算哪边关键字出现的多就按次数多的定义。比如正常邮件关键字有3个,垃圾邮件关键字有20个,那么这邮件是垃圾邮件的概率大于这是正常邮件的概率,那就定义这邮件为垃圾邮件。
这个对于英文来说非常容易实现,但对于中文来说就不是那么回事了,因为中华汉字博大精深嘛,关键字非常不好找,算法的学习也是一件非常耗时的工作。所以这儿呢,我就简单实现一个类似的东西吧,我将实现,判断一句话的情感状态。
首先是分词,我选择friso;然后是情感词库,我找的一个网上的情感词汇本体库。这些东西在上面的源代码下载里面已经包括了。
继续阅读C++机器学习(3)朴素贝叶斯

C++机器学习(2)决策树

部分资料下载地址: http://pan.baidu.com/s/1bpsgt5t 提取码fwxf
源码下载地址:https://github.com/fawdlstty/hm_ML

M$大大前段时间弄了个小冰读心术,大概意思是通过15个问题,回答是、否、不知道,小冰就可以猜出你想的是什么人物。连接在这 微软小冰·读心术
这种逻辑非常像二叉决策树,通过递归(高手也可以用迭代)判断特征,最终确定目标类型。每次判断的分支有两种类型,一种是二叉决策树,一种是多叉决策树,它们之间并没有绝对的优劣之差,各自有各自的优点。
示例决策如下图所示:
20160422211450
上图只是一个比较精简的决策的示例,可见决策树从速度上效率比之前的k-近邻算法强很多。实际上决策树也就是k-近邻算法的优化版,在损失一定精度情况下,可以使判断速度减少一个数量级。
继续阅读C++机器学习(2)决策树

C++机器学习(1)k-近邻算法

部分资料下载地址: http://pan.baidu.com/s/1bpsgt5t 提取码fwxf
源码下载地址:https://github.com/fawdlstty/hm_ML

又是一个神秘的领域,对于C++程序猿来说,机器学习就像小白对C++一样。什么手写识别,什么自动驾驶,对于C++程序猿来说,几乎是不可能的实现。但如果了解原理之后,机器学习也就这么回事。这篇文章简要介绍机器学习以及用C++实现一个简单的机器学习算法——k-近邻算法。
首先说一下变种病毒。变种病毒的核心实现是动态随机修改指令,用于绕过几乎所有的特征码杀毒引擎,实现上并不是病毒自身会进化,而是仅仅修改了实现方式。从汇编角度上来说,比如以下代码:

1
mov eax, 10h

以上代码的含义是,将16这个立即数放在eax寄存器里面。变种核心模块将以上代码替换为如下形式

1
2
3
4
5
push ebx
mov ebx, 12h
sub ebx, 2h
mov eax, ebx
pop ebx

以上代码的实现效果与上面那一行代码完全相同。如果之前的代码是杀毒引擎标记的特征的话,那么变种病毒经过这次变种后,杀毒引擎就找不到特征了,于是实现了过杀毒引擎的效果。虽然变种病毒听起来很恐怖,但实际上病毒所实现的效果并不会改变,也就是说,以前没有的功能,病毒并不会在自我升级中产生。
继续阅读C++机器学习(1)k-近邻算法

C++11:std::bind实现参数动态绑定

参数动态绑定在实际编程中用的不多,但在特定情况下非常有用。这个功能的意思是,将函数与参数绑定,下次调用时可以不用再次麻烦的传递参数。首先给出一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <string>
#include <functional>
using namespace std;
 
void func (int i, int j) {
    cout < < "i = " << i << ", j = " << j << endl;
}
 
int main(int argc, char* argv[]) {
    function<void (int, int)> f = func;
    f (1, 2);
    return 0;
}</functional></string></iostream>

结果为i = 1, j = 2
以上例子是使用函数对象保存函数地址,然后调用函数对象的示例代码,下面我让函数对象f与参数进行绑定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <string>
#include <functional>
using namespace std;
 
void func (int i, int j) {
    cout < < "i = " << i << ", j = " << j << endl;
}
 
int main(int argc, char* argv[]) {
    function<void ()> f = bind(func, 1, 2);
    f ();
    return 0;
}</functional></string></iostream>

结果为i = 1, j = 2
由于已经绑定了参数1和2,所以在实际调用时不用再次赋值。注意函数对象的声明。
继续阅读C++11:std::bind实现参数动态绑定

C++实现高效字符串查找算法

最近想到一个关于高效字符串查找算法的设想,然后果断实现之,算法基于哈希表,用于源字符串特别长的情况,查找的子字符串越长、越没规律,那么速度越快。可能已经有人做过,不过我撸代码前还没听说过类似算法,算是一种轮子吧。
基本实现的思路是:首先建立一个hash_map,然后将子字符串所有字符及位置录入字符串中,如下图所示:
20160401212342
对于需要查找的字符串(比如在很长的字符串文本中查找“abcdefga”这一串字符),构建如上所示哈希表,键值名为子字符串出现的字符,值为出现的位置。
构建好之后呢,就好玩了,我只说说正向查找原理,逆向查找类似。首先,来一个假设,我就假设源字符串为“abababcdefgaaaaa”这样吧,第一次,取源字符串中,(子字符串长度-1)这个位置的字符,值为d,然后取哈希表的值,为3,那么,将源字符串中7-3的位置开始,与子字符串相比较,比较结果较满意,第一次就查找成功,那么直接返回7-3=4。
继续阅读C++实现高效字符串查找算法

C++中Base64编码解码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
template<typename CharT>
class base64 {
public:
    //base64 加密
    static bool encode (std::basic_string<charT>& _old, std::basic_string<charT>& _new) {
        static charT _code [] = {
            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',   'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
            'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',   'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
            'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',   'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
            'w', 'x', 'y', 'z', '0', '1', '2', '3',   '4', '5', '6', '7', '8', '9', '+', '/',
        };
        ptrdiff_t i, len = _old.length ();
        _new.resize (((len % 3 ? 1 : 0) + len / 3) * 4);
        //主编码循环
        for (i = 0; i < len / 3; ++i) {
            _new [i * 4] = _code [_old [i * 3] >> 2];
            _new [i * 4 + 1] = _code [((_old [i * 3] & 0x03) << 4) | (_old [i * 3 + 1] >> 4)];
            _new [i * 4 + 2] = _code [((_old [i * 3 + 1] & 0x0F) << 2) | (_old [i * 3 + 2]) >> 6];
            _new [i * 4 + 3] = _code [_old [i * 3 + 2] & 0x3F];
        }
        //长度不为3的倍数
        if (len % 3) {
            //第一字节肯定不会溢出,故不检查边界
            _new [i * 4] = _code [_old [i * 3] >> 2];
            _new [i * 4 + 1] = _code [((_old [i * 3] & 0x03) << 4) | (i * 3 + 1 < len ? _old [i * 3 + 1] >> 4 : 0)];
            //倒数第二位可能为'='
            if (1 == len % 3)
                _new [i * 4 + 2] = '=';
            else
                _new [i * 4 + 2] = _code [(i * 3 + 1 < len ? (_old [i * 3 + 1] & 0x0F) << 2 : 0)];
            //末位肯定为'='
            _new [i * 4 + 3] = '=';
        }
        return true;
    }
 
    //base64 解密
    static bool decode (std::string& _old, std::string& _new) {
        static charT _ucode [] = {
            0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
            0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  0,  0,  0,  0,  0,
            0,  0,  0,  0,  0,  0,  0,  0,    0,  0,  0,  62, 0,  0,  0,  63,
            52, 53, 54, 55, 56, 57, 58, 59,   60, 61, 0,  0,  0,  64, 0,  0,
            0,  0,  1,  2,  3,  4,  5,  6,    7,  8,  9,  10, 11, 12, 13, 14,
            15, 16, 17, 18, 19, 20, 21, 22,   23, 24, 25, 0,  0,  0,  0,  0,
            0,  26, 27, 28, 29, 30, 31, 32,   33, 34, 35, 36, 37, 38, 39, 40,
            41, 42, 43, 44, 45, 46, 47, 48,   49, 50, 51, 0,  0,  0,  0,  0,
        };
        ptrdiff_t i, len = _old.length ();
        ptrdiff_t len2 = len / 4 * 3;
        //判断末位是否有等号、有几个等号
        if ('=' == _old [len - 2])
            len2 -= 2;
        else if ('=' == _old [len - 1])
            len2--;
        else if (len % 4)
            len2 += (len % 4 - 1);
        _new.resize (len2);
        //主解密循环
        for (i = 0; i < len2 / 3; ++i) {
            _new [i * 3] = (_ucode [_old [i * 4]] << 2) | (_ucode [_old [i * 4 + 1]] >> 4);
            _new [i * 3 + 1] = ((_ucode [_old [i * 4 + 1]] & 0x0F) << 4) | (_ucode [_old [i * 4 + 2]] >> 2);
            _new [i * 3 + 2] = ((_ucode [_old [i * 4 + 2]] & 0x03) << 6) | (_ucode [_old [i * 4 + 3]]);
        }
        //末位为一个或两个等号的情况,这时候不能通过主解密循环进行解密
        if (len2 % 3) {
            _new [i * 3] = (_ucode [_old [i * 4]] << 2) | (_ucode [_old [i * 4 + 1]] >> 4);
            if (2 == len % 3)
                _new [i * 3 + 1] = ((_ucode [_old [i * 4 + 1]] & 0x0F) << 4) | (_ucode [_old [i * 4 + 2]] >> 2);
        }
        return true;
    }
};

C++中std::string实现trim、format等函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
////////////////////////////////////////////////////////////////////////////////
//
//  File Name:      String.hpp
//  Class Name:     hString
//  Description:    用于字符串相关扩展操作
//  Author:         Fawdlstty
//
//  Date:           Nov 19, 2016
//  Log:            Create this file.
//
////////////////////////////////////////////////////////////////////////////////
 
 
 
#ifndef __STRING_HPP__
#define __STRING_HPP__
 
 
 
#include <string>
#include <cstdarg>
 
 
 
template<typename charT>
class hString {
public:
    //清除字符串开始部分空格
    static void trimLeft (std::basic_string<charT> &str) {
        str.erase (0, str.find_first_not_of (' '));
    }
 
    //清除字符串结束部分空格
    static void trimRight (std::basic_string<charT> &str) {
        str.erase (str.find_last_not_of (' ') + 1);
    }
 
    //清楚两端空格
    static void trim (std::basic_string<charT> &str) {
        str.erase (0, str.find_first_not_of (' '));
        str.erase (str.find_last_not_of (' ') + 1);
    }
 
    //删除字符串中指定字符
    static void erase (std::basic_string<charT> &str, const charT &charactor) {
        str.erase (remove_if (str.begin (), str.end (), bind2nd (std::equal_to<charT> (), charactor)), str.end ());
    }
 
    //替换字符串中指定字符串
    static int replace (std::basic_string<charT> &str, const std::basic_string<charT> &strObj, const std::basic_string<charT> &strDest) {
        int ret = 0;
        charT pos = str.find (strObj);
        while (pos != std::basic_string<charT>::npos) {
            ret++;
            str.replace (pos, strObj.size (), strDest);
            pos = str.find (strObj);
        }
        return ret;
    }
 
    //一行中的字符串截断,并可转为其他类型
    template<typename T>
    static int split_aLine_conv (const std::basic_string<charT> &str, std::vector<T> &seq, charT separator) {
        if (str.empty ()) return 0;
        int count = 0;
        std::basic_stringstream<charT> bs (str);
        for (std::basic_string<charT> s; std::getline (bs, s, separator); count++) {
            typename T val;
            std::basic_stringstream<charT> bss (s);
            bss >> val;
            seq.push_back (val);
        }
        return count;
    }
 
    //字符串截断
    static void split (std::basic_string<charT> s, std::vector<std::basic_string<charT> >& v, char ch = ' ') {
        ptrdiff_t start = 0, p, len = s.length ();
        do {
            p = s.find (ch, start);
            if (p == -1) p = len;
            s [p] = '\0';
            if (s [start] != '\0') v.push_back (&s [start]);
            start = p + 1;
        } while (start < len);
    }
 
    //字符串格式化
    static std::basic_string<charT> format (std::basic_string<charT> fmt_str, ...) {
        //来源:http://stackoverflow.com/questions/2342162/stdstring-formatting-like-sprintf
        ptrdiff_t final_n, n = ((ptrdiff_t) fmt_str.size ()) * 2;
        std::basic_string<charT> str;
        std::unique_ptr<charT []> formatted;
        va_list ap;
        while (1) {
            formatted.reset (new charT [n]);
            //strcpy_s (&formatted [0], fmt_str.size (), fmt_str.c_str ());
            va_start (ap, fmt_str);
            final_n = vsnprintf_s (&formatted [0], n, _TRUNCATE, fmt_str.c_str (), ap);
            va_end (ap);
            if (final_n < 0 || final_n >= n)
                n += abs (final_n - n + 1);
            else
                break;
        }
        return std::basic_string<charT> (formatted.get ());
    }
};
 
 
 
typedef hString<char> hStringA;
typedef hString<wchar_t> hStringW;
#ifdef _UNICODE
typedef hStringW hString_t;
typedef std::wstring string_t;
#else
typedef hStringA hString_t;
typedef std::string string_t;
#endif
 
 
 
#endif //__STRING_HPP__

ASP.Net 后台访问Cookie的封装

这是一个类,用于提供后台C#访问Cookie,函数不多,只有几个,包括设置、获取、修改。具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
using System;
using System.Collections.Generic;
using System.Web;
using System.Text;
 
namespace SqlHelper {
	public class Cookie2 {
		/// <summary>
		/// 设置Cookie的值,关闭Session后释放
		/// </summary>
		/// <param name="name">名称</param>
		/// <param name="value">Cookie值</param>
		/// <param name="response">HttpResponse</param>
		public static void Set (HttpResponse response, string name, string value) {
			HttpCookie cookie = new HttpCookie (name);
			cookie.Values.Add (name, value);
			response.AppendCookie (cookie);
		}
 
 
 
		/// <summary>
		/// 设置Cookie的值,包含过期时间
		/// </summary>
		/// <param name="name">名称</param>
		/// <param name="value">Cookie值</param>
		/// <param name="expiredays">过期时间</param>
		/// <param name="response">HttpResponse</param>
		public static void Set (HttpResponse response, string name, string value, DateTime expiredays) {
			HttpCookie cookie = new HttpCookie (name);
			cookie.Expires = expiredays;
			cookie.Values.Add (name, value);
			response.AppendCookie (cookie);
		}
 
 
 
		/// <summary>
		/// 获取Cookie值
		/// </summary>
		/// <param name="name">名称</param>
		/// <param name="request">HttpRequest</param>
		/// <returns>Cookie的值</returns>
		public static string Get (HttpRequest request, string name) {
			if (request.Cookies[name] != null) {
				return request.Cookies[name].Values.toString();
			} else {
				return null;
			}
		}
 
 
 
		/// <summary>
		/// 删除Cookie
		/// </summary>
		/// <param name="name">名称</param>
		/// <param name="response">HttpResponse</param>
		/// <param name="request">HttpRequest</param>
		public static void Delete (HttpResponse response, HttpRequest request, string name) {
			HttpCookie cookie = request.Cookies[name];
			if (cookie != null) {
				cookie.Expires = DateTime.Now.AddDays (-1);
				response.AppendCookie (cookie);
			}
		}
 
 
 
		/// <summary>
		/// 修改Cookie的值
		/// </summary>
		/// <param name="name">名称</param>
		/// <param name="value">Cookie值</param>
		/// <param name="response">HttpResponse</param>
		/// <param name="request">HttpRequest</param>
		public static void Modify (HttpResponse response, HttpRequest request, string name, string value) {
			HttpCookie cookie = request.Cookies[name];
			if (cookie != null) {
				cookie.Values[name] = value;
			}
			response.AppendCookie (cookie);
		}
	}
}