std::variant 类似 union

using IntFloatString = std::variant<int, float, std::string>; // 定义支持int、float、string三个类型,并取一个别名
//初始化一个variant
TEST_F(InitVariant) {

IntFloatString i = 10;
ASSERT_EQ(10, std::get<int>(i) );

IntFloatString f = 20.0f;
ASSERT_EQ(20.0f, std::get<float>(f) );

IntFloatString s = "hello world";
ASSERT_EQ("hello world", std::get<std::string>(s));
}

应用场景

同一个函数,可能返回不同类型的返回值。

多态

用来打包可变参数的

有四种语义

unary right fold (pack op …)
unary left fold (… op pack)
binary right fold (pack op … op init)
binary left fold (init op … op pack)
template<typename... Args>
auto sub_val_right(Args&&... args) {
return (args - ...);
}


template<typename... Args>
auto sub_val_left(Args&&... args) {
return (... - args);
}

auto t = sub_val_right(2,3,4); //(2-(3-4)) = 3
auto t1 = sub_val_left(2,3,4); //((2-3)-4) = -5
template<typename... Args>
auto sub_one_left(Args&&... args) {
return (1 - ... - args);
}

template<typename... Args>
auto sub_one_right(Args&&... args) {
return (args - ... - 1);
}

auto t = sub_one_left(234);// (((1-2)-3)-4) = -8
auto t1 = sub_one_right(234);//(2-(3-(4-1))) = 2

20200327_084455.png

GPL/GNU

GPL 要求提供源码,所以不适合商用

GNU 通用公共许可证(英语:GNU General Public License,缩写 GNU GPL 或 GPL)
是被广泛使用的自由软件许可证,给予了终端用户运行、学习、共享和修改软件的自由
GPL是在分发软件的时候有约束,就是在分发二进制的时候必须以同样的GPL分发代码。(分发包括公开提供下载和商业使用等)

GPL协议的主要内容是只要在一个软件中使用(”使用”指类库引用,修改后的代码或者衍生代码)GPL 协议的产品,则该软件产品必须也采用GPL协议,既必须也是开源和免费。这就是所谓的”传染性”。GPL协议的产品作为一个单独的产品使用没有任何问题,还可以享受免费的优势。

LGPL

LGPL是GPL的一个为主要为类库使用设计的开源协议。和GPL要求任何使用/修改/衍生之GPL类库的的软件必须采用GPL协议不同。LGPL 允许商业软件通过类库引用(link)方式使用LGPL类库而不需要开源商业软件的代码。这使得采用LGPL协议的开源代码可以被商业软件作为类库引用并发布和销售。

但是如果修改LGPL协议的代码或者衍生,则所有修改的代码,涉及修改部分的额外代码和衍生的代码都必须采用LGPL协议。因此LGPL协议的开源代码很适合作为第三方类库被商业软件引用,但不适合希望以LGPL协议代码为基础,通过修改和衍生的方式做二次开发的商业软件采用。

GPL/LGPL都保障原作者的知识产权,避免有人利用开源代码复制并开发类似的产品

BSD 3-Clause License

可以商用

MIT

MIT是和BSD一样宽范的许可协议,作者只想保留版权,而无任何其他了限制.也就是说,你必须在你的发行版里包含原许可协议的声明,无论你是以二进制发布的还是以源代码发布的.

BSD开源协议(original BSD license、FreeBSD license、Original BSD license)

当你发布使用了BSD协议的代码,或则以BSD协议代码为基础做二次开发自己的产品时,需要满足三个条件:

  1. 如果再发布的产品中包含源代码,则在源代码中必须带有原来代码中的BSD协议。
  2. 如果再发布的只是二进制类库/软件,则需要在类库/软件的文档和版权声明中包含原来代码中的BSD协议。
  3. 不可以用开源代码的作者/机构名字和原来产品的名字做市场推广。

Mozilla Public License 2.0 (MPL-2.0)

可以商用,不可修改代码

boost software license

许库用户将Boost用于任何用途,包括商业用途和非商业用途。用户无须支付任何费用,即可享有Boost的全部功能。

如果使用 vc 可以使用下面的函数

// For 16 bit numbers:
unsigned short _byteswap_ushort(unsigned short value);
// For 32 bit numbers:
unsigned long _byteswap_ulong(unsigned long value);
// For 64 bit numbers:
unsigned __int64 _byteswap_uint64(unsigned __int64 value);

#include <climits>

template <typename T>
T swap_endian(T u)
{
static_assert (CHAR_BIT == 8, "CHAR_BIT != 8");

union
{
T u;
unsigned char u8[sizeof(T)];
} source, dest;

source.u = u;

for (size_t k = 0; k < sizeof(T); k++)
dest.u8[k] = source.u8[sizeof(T) - k - 1];

return dest.u;
}

swap_endian<uint32_t>(42);
#ifdef _MSC_VER

#include <stdlib.h>
#define bswap_32(x) _byteswap_ulong(x)
#define bswap_64(x) _byteswap_uint64(x)

#elif defined(__APPLE__)

// Mac OS X / Darwin features
#include <libkern/OSByteOrder.h>
#define bswap_32(x) OSSwapInt32(x)
#define bswap_64(x) OSSwapInt64(x)

#elif defined(__sun) || defined(sun)

#include <sys/byteorder.h>
#define bswap_32(x) BSWAP_32(x)
#define bswap_64(x) BSWAP_64(x)

#elif defined(__FreeBSD__)

#include <sys/endian.h>
#define bswap_32(x) bswap32(x)
#define bswap_64(x) bswap64(x)

#elif defined(__OpenBSD__)

#include <sys/types.h>
#define bswap_32(x) swap32(x)
#define bswap_64(x) swap64(x)

#elif defined(__NetBSD__)

#include <sys/types.h>
#include <machine/bswap.h>
#if defined(__BSWAP_RENAME) && !defined(__bswap_32)
#define bswap_32(x) bswap32(x)
#define bswap_64(x) bswap64(x)
#endif

#else

#include <byteswap.h>

#endif

ref.1

正常项目,一般都是网线tcp通讯的那种,官方叫 iso on tcp 这种方式
西门子的做法和 现在的大众软件方法类似,开放一个默认端口,是102,可以同时连接多个客户端;
tcp 客户端连上西门子的102端口后,必须做一个特定报文的交互,然后才能做正常的读取操作;

可能由于西门子的102端口是1对多的,所以它比较拽,一旦发现通讯数据格式或内容不正确,不但不回复,而且直接跟你把通讯通道断开,
不理你了; 三菱遇到异常报文时,通讯不会断的,只是回复你异常数据,并且有异常代码;

解析的是以 0x32 开始的报文结构

借助WireShark抓包,可以看到,S7Comm 以太网协议基于OSI模型:

阅读全文 »

在对话框程序中使用。

ref.1

  1. 资源管理其中,拖拽自定义控件到对话框中
  2. 右键菜单创建 class,继承至 CWnd
  3. 比较重要的一步,需要注册自定义的控件,并且必须在构造函数里面注册
#define WNDCLASS_NAME (L"CCanvas")

BOOL CCanvas::RegisterWndClass()
{
WNDCLASS windowclass;
HINSTANCE hInst = AfxGetInstanceHandle();

//Check weather the class is registerd already
if (!(::GetClassInfo(hInst, WNDCLASS_NAME, &windowclass)))
{
//If not then we have to register the new class
windowclass.style = CS_DBLCLKS;// | CS_HREDRAW | CS_VREDRAW;
windowclass.lpfnWndProc = ::DefWindowProc;
windowclass.cbClsExtra = windowclass.cbWndExtra = 0;
windowclass.hInstance = hInst;
windowclass.hIcon = NULL;
windowclass.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
windowclass.hbrBackground = ::GetSysColorBrush(COLOR_WINDOW);
windowclass.lpszMenuName = NULL;
windowclass.lpszClassName = WNDCLASS_NAME;

if (!AfxRegisterClass(&windowclass))
{
AfxThrowResourceException();
return FALSE;
}
}

return TRUE;
}

CCanvas::CCanvas()
{
RegisterWndClass();
}
  1. 绑定类和自定义控件。右键单击-属性-class 里面填写类定义里面的 “CCanvas”
  2. 数据绑定,在对话框主程序中添加
CCanvas m_canvas;//This is our custom control

void CdrawDemoDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_STATIC_FRAME, m_ctrl_draw);
DDX_Control(pDX, IDOK, m_btn_ok);
DDX_Control(pDX, IDC_CUSTOM1, m_canvas);
}

在对话框程序中使用。

ref.1

  1. 资源管理其中,拖拽自定义控件到对话框中
  2. 右键菜单创建 class,继承至 CWnd
  3. 比较重要的一步,需要注册自定义的控件,并且必须在构造函数里面注册
#define WNDCLASS_NAME (L"CCanvas")

BOOL CCanvas::RegisterWndClass()
{
WNDCLASS windowclass;
HINSTANCE hInst = AfxGetInstanceHandle();

//Check weather the class is registerd already
if (!(::GetClassInfo(hInst, WNDCLASS_NAME, &windowclass)))
{
//If not then we have to register the new class
windowclass.style = CS_DBLCLKS;// | CS_HREDRAW | CS_VREDRAW;
windowclass.lpfnWndProc = ::DefWindowProc;
windowclass.cbClsExtra = windowclass.cbWndExtra = 0;
windowclass.hInstance = hInst;
windowclass.hIcon = NULL;
windowclass.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
windowclass.hbrBackground = ::GetSysColorBrush(COLOR_WINDOW);
windowclass.lpszMenuName = NULL;
windowclass.lpszClassName = WNDCLASS_NAME;

if (!AfxRegisterClass(&windowclass))
{
AfxThrowResourceException();
return FALSE;
}
}

return TRUE;
}

CCanvas::CCanvas()
{
RegisterWndClass();
}
  1. 绑定类和自定义控件。右键单击-属性-class 里面填写类定义里面的 “CCanvas”
  2. 数据绑定,在对话框主程序中添加
CCanvas m_canvas;//This is our custom control

void CdrawDemoDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_STATIC_FRAME, m_ctrl_draw);
DDX_Control(pDX, IDOK, m_btn_ok);
DDX_Control(pDX, IDC_CUSTOM1, m_canvas);
}

初三学三角函数:正弦,余弦和正切都是研究三角形边角关系的。等你学的时候会要求你知道角会求边,知道边会求角,比如说求船的航行路程,仰角俯角求建筑物高度,还有,有时还会和勾股定理一起用

名称来源

来源是文言文。把词语拆成字逐个分析。“弦”代表长,也就是斜边,从“勾三股四弦五”中迁移过来。“正”就是正对,表示直角三角形中角的对边。“余”代表相邻,表示直角三角形中与角相邻的直角边。“切”有垂直之意,在圆的切线中有体现。这样一来,正弦就是对边比斜边,余弦就是邻边比斜边,正切就是对边比(与对边垂直的)邻边。我们常说切割,在数学里,切和割是相差很远的,比如切线和割线。所以在三角函数里,切割相反。

用途

从已知两边求角度

例子
梯子搁在墙上,如图。梯子与墙之间的 角度 是多少?

20200317_124139.png

例子:在这个梯子的例子,我们知道:
角 “x” 的 对边的长度:2.5
最长的边(斜边)的长度:5

$Sin (x) = 对边 / 斜边 = 2.5 / 5 = 0.5$

解方程!

$sin(x) = 0.5$

我们可以重写为:

$x = sin^{-1}(0.5)$

我们用计算器来做:输入 0.5,按 $sin^{-1}$ 键,答案便出来了:

$x = 30°$

但…… $sin^{-1}$ 的意思是什么?
正弦函数 “sin” 以角度为输入来计算 “对边/斜边” 的比,

20200317_134548.png

$sin^{-1}$(叫 “反正弦”)是正弦的相反……
……它以 “对边/斜边” 的比为输入来计算角度。

例子:
正弦函数:sin(30°) = 0.5
反正弦函数:sin-1(0.5) = 30°

正弦、余弦和正切

正弦 (sine), 余弦 (cosine) 和 正切 (tangent) (英语符号简写为 sin, cos 和 tan) 是 直角三角形 边长的比:

20200818_111751.png

AllocConsole 为调用进程分配一个新的控制台

#ifdef _DEBUG  
AllocConsole();
_cprintf("Debuging....\r\n");
#endif

HANDLE hOutputHandle=GetStdHandle(STD_OUTPUT_HANDLE);//获得控制台输出句柄
DWORD nRet=0;
TCHAR buf[100]={0};//用来输出字符的缓冲区
lstrcpy(buf,_T("Hello"));
WriteConsole(hOutputHandle,buf,lstrlen(buf),&nRet,NULL);

// 退出时释放
FreeConsole();

AllocConsole 为调用进程分配一个新的控制台

#ifdef _DEBUG  
AllocConsole();
_cprintf("Debuging....\r\n");
#endif

HANDLE hOutputHandle=GetStdHandle(STD_OUTPUT_HANDLE);//获得控制台输出句柄
DWORD nRet=0;
TCHAR buf[100]={0};//用来输出字符的缓冲区
lstrcpy(buf,_T("Hello"));
WriteConsole(hOutputHandle,buf,lstrlen(buf),&nRet,NULL);

// 退出时释放
FreeConsole();