SanXian

简单.确定.稳定.三联生活

0%

0x01 时间函数之间的关系

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
struct tm
{
    int tm_sec;    // 代表目前秒数,正常范围0-59,但允许至61秒;
    int tm_min;    // 代表目前分数,范围为0-59。
    int tm_hour;   // 从午夜算起的小时数,范围为0-23。
    int tm_mday;   // 目前月份的日数,范围为1-31。
    int tm_mon;    // 代表目前月份,从一月算起,范围为0-11。
    int tm_year;   // 从1900年算起至今的年数。比如(时间戳1970-01-02 10:23:09,该值为70)。
    int tm_wday;   // 一星期中的日数,从星期日算起,范围为0-6。
    int tm_yday;   // 从1月1日算起至今的天数,范围为:0-365。
    int tm_isdst;  // 日光节约时间的旗标。
};

Shell编程中常用的文件描述符有3个:

0:stdin,标准输入,默认指的是键盘输入

1:stdout,标准输出,默认指的是屏幕输出

2:stderr,标准错误输出,默认值得是屏幕输出

简单介绍STL对集合操作有标准的算法:

  • 交集set_intersection
  • 并集set_union
  • 差集set_difference
  • 对称差集set_symeetric_difference。

针对这里提及的四个集合运算必须特别注意:

  • 1、第一个算法需保证第一集合和第二集合有序,并从小到大排序,内部使用默认“<”操作符比较元素大小;
  • 2、第二个算法需保证第一集合和第二集合有序,排序方式参照Compare确定,内部使用Compare比较元素大小。

在C++11之前,要实现函数对象或者仿函数,主要参考《C++设计新思维》中的Loki库,它采用模板推导的方式来实现。虽然Loki可以模拟函数对象,但其代码看起来比较晦涩,使用又不方便。在C++11以后,开始原生支持函数对象,新标准中的用法简单清晰,所有的可调用对象有了统一的调用方式,极易上手。本文总结函数对象的各种使用方法。

本文记录现代C++使用到的图书以及相关网站。

0x01 相关网站

  • C++ reference

https://en.cppreference.com/w

https://zh.cppreference.com/w

https://zh.cppreference.com/w/cpp/11

https://zh.cppreference.com/w/cpp/14

https://zh.cppreference.com/w/cpp/17

https://zh.cppreference.com/w/cpp/20

https://zh.cppreference.com/w/cpp/23

https://zh.cppreference.com/w/cpp/26

  • Standard C++ Library reference

https://cplusplus.com/reference

隐式类型转换带来的问题

我们首先看下面的这个例子,它可编译也可执行,最终结果是“TDemo::print 55”。有理由推断,实例化一个对象时,编译器自动将55这个整数转换成了“class TDemo”。类TDemo定义了一个单参数构造函数,而C++标准中,“单参数构造函数,可以完成从形参到该类型的一个隐式转换”,所以编译器能够完成从int类型到TDemo的类型转换。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>

class TDemo
{
public:
    TDemo(int num);
    void print() const 
    { 
        std::cout << "TDemo::print "<< i_num << std::endl; 
    }

private:
    int i_num;
};

TDemo(int num):i_num(num){}

int main()
{
    TDemo demo = 55;
    demo.print();

    return 0;
}

C++继承机制的相关知识点

继承机制,就是利用已有的数据类型来定义新的数据类型,新数据类型将拥有基类的成员。派生类可以从一个基类派生,也可以从多个基类派生。从一个基类派生的继承称为单继承;从多个基类派生的继承称为多继承。

单继承语法:

1
2
3
4
class <派生类名称>:<继承方式><基类名>
{
    //派生类新定义成员
}; 

多继承语法:

1
2
3
4
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,......
{
    //派生类新定义成员
}; 

C++ Primer的强烈建议

强制类型转换关闭或挂起了正常的类型检查。强烈建议避免使用强制类型转换,不依赖类型转换也能写出很好的C++程序。

这个建议在如何看待 reinterpret_cast 的使用时非常重要。此类强制转换总是非常危险的。相似地,使用价格const_cast也总是预示着设计权限。设计合理的系统应不需要使用强制转换抛弃const特性。其他的强制转换,如static_cast和dynamic_cast,各有各的用途,但都不应频繁使用。每次使用强制转换前,程序员应该仔细考虑是否还有其他不同的方法可以达到同一目的。如果非强制转换不可,则应限制强制转换值的作用域,并且记录所有假定涉及的类型,这样能减少错误发生的机会。

导语:C++中用“虚”的来命名的概念,涉及:

  • 虚函数
  • 虚析构函数
  • 纯虚函数
  • 虚基类

本文简要的说明下在面临什么样的问题下使用相应的技术、这些概念又是如何解决问题的。

基础图书

书名ISBN作者出版社出版日期备注
C++ Primer 中文版 第5版9787121155352[美]李普曼电子工业出版社2013-09-01P
C++ Templates 第2版 中文版9787115601513[美]范德沃德,约祖蒂斯人民邮电出版社2024-01-01
C++ Templates 第2版 英文版9787121155352[美]范德沃德,约祖蒂斯人民邮电出版社2018-05-01P
C++ Templates 中文版9787115479938[美]范德沃德,约祖蒂斯人民邮电出版社2013-04-01P
深入应用C++11:代码优化与工程级应用9787111500698祁宇机械工业出版社2015-05-01P,JV
深入理解C++11:C++ 11新特性解析与应用9787111426608Michael Wong机械工业出版社2013-06-01P,JV
现代C++语言核心特性解析9787115564177谢丙堃人民邮电出版社2021-10-01P,JV
学习C++20(中文版)9787302625438[美]Paul J. Deitel,[美]Harvey M. Deitel清华大学出版社2023-05-01
标准C++输入输出流与本地化9787115090522万东旭,陈冀康人民邮电出版社2001-04-01P
C++ Core Guidelines解析9787302635772[德]赖纳·格林清华大学出版社2023-07-01

参考图书

书名ISBN作者出版社出版日期备注
C和指针9787115522689[美]肯尼斯·里科人民邮电出版社2020-09-01P
C陷阱与缺陷9787115521279[美]安德鲁·凯尼格人民邮电出版社2020-08-01P
C专家编程9787115521323[美]彼得·范德林登人民邮电出版社2020-09-01P
C语言接口与实现 创建可重用软件的技术9787115402523[美]戴维 R.汉森人民邮电出版社2022-07-01

VSCode是微软出品的编辑器,简单清凉、扩展丰富。vscode依赖扩展完成各种丰富的功能实现,像胶水一样将扩展整合起来。同时支持跨平台,可以在Windows、Linux以及Mac上使用。本文记录相关的使用方法。

背景

使用天翼云盘的同步盘,我将同步目录设置为H:\Cloud\TySync,但使用同步盘较为频繁,每次按目录查找文件都比较繁琐。所以就想将这个同步目录映射为一个虚拟盘符,在资源管理器首页双击盘符即可进入同步盘。

于是网上找到了“vSubst”这个小工具,可以简单的将文件夹映射为虚拟盘符。


下载地址:https://www.onlinedown.net/soft/1915.htm

Win11激活强制要求联网以及登录,在不设置的情况下,还不能跳过,如下方法教我们初装系统时跳过该两项设置。

在Windows上编译某些软件时,会提示我们使用Vs2017开发人员工具,而非普通的CMD窗口。

一般我们会从开始菜单找到“适用于VS2017的x64本机工具命令提示”,打开后再多次使用cd命令进入软件的编译目录。

本文记录一种在右键菜单中,增加打开“适用于VS2017的x64本机工具命令提示”的快速入口。

代码统计我们时常用到,比如统计代码行数、注释行数、空行数、文件大小等等。本文介绍Windows和Linux上常用的代码工具。

如SecureCRT一般,WindTerm是一款多协议、多功能、跨平台的终端仿真协议程序,用于Windows/Mac/Linux等环境登录UNIX/Linux服务器主机。与其他终端工具相比,最大特点就是开源、无论商业或者非商业应用均免费,特别适合一般小型公司使用

如WinTerm官方所言“WindTerm is a partial open source project, and the source will be gradually opened.”,目前它是部分开源,其他代码逐步计划开源。

WindTerm的主要功能:

  • 支持 SSH、Telnet、Tcp、Shell、Serial
  • 支持 SSH v2、Telnet、Raw Tcp、串行、Shell 协议。
  • 会话认证时支持 SSH 自动执行。
  • 支持 SSH ControlMaster。
  • 支持 SSH ProxyCommand 或 ProxyJump。
  • 支持 SSH 代理转发。
  • 支持使用密码、公钥、键盘交互、gssapi-with-mic 的 SSH 自动登录。
  • 支持 X11 转发。
  • 支持直接/本地端口转发、反向/远程端口转发和动态端口转发。
  • 支持 XModem、YModem 和 ZModem。
  • 集成 sftp、scp 客户端,支持下载、上传、删除、重命名、新建文件/目录等。
  • 集成本地文件管理器,支持移动到、复制到、复制自、删除、重命名、新建文件/目录等。
  • 支持 Windows Cmd、PowerShell 和 Cmd、PowerShell 作为管理员。
  • 支持 Linux bash、zsh、powershell core 等。
  • 支持 MacOS bash、zsh、powershell core 等。

更多: https://github.com/kingToolbox/WindTerm/blob/master/README.md

官网: https://github.com/kingToolbox/WindTerm

下载: https://github.com/kingToolbox/WindTerm/releases

本次对Hexo的修改,主要完成如下两个功能:

  • 第一,Hexo的分类默认使用名称按照字典排序,我希望是自己可以方便指定分类序号,从而按序号排序显示;
  • 第二,Hexo的分类名称需要直接写在Post文档categories的字段,后续如果需要修改某个分类名称,需要修改多个文档,我希望是给每个分类起个别名,Post文档中使用该别名,在特定的文档中定义别名和真实名称的映射关系,然后Hexo生成静态页面时,Hexo自动对别名进行替换。

本博客是由Hexo来编译发布的,这里记录下Hexo首次安装和重新下载博客代码之后重置环境的方法。

首次安装Hexo

第一步,安装Node.js。我们可以使用腾讯电脑管家,搜索nodejs来安装。或者到Node.js的官方网站下载来安装。

我们通常使用scp在服务器之间的copy数据,但需要每次输入账户密码才能完成copy。

比如我们欲将test.cpp文件从192.168.9.130拷贝到192.168.128服务器,一般执行流程如下图所示:

有时我们需要在脚本中自动将某些数据传输到另外一台机器上,每次输入密码则不那么方便,所以我们需要实现scp服务器间免密拷贝数据。

实现scp服务器间的密码拷贝数据,其方法一般有如下两步:

第一步,在本机生成SSH公私钥;

第二步,将本机生成的公钥拷贝到目标机器上,然后将公钥内容加入对应账号的 /home/{user}/.ssh/authorized_keys 文件内;

OpenSSH有两种认证方式:基于口令认证和基于密钥认证。 基于口令的认证相对简单,仅需在SSH客户端登录时输入密码即可。在某些场景,比如登录公司服务器,一般需要我们通过每人的密钥登录。 本文基于我经常使用的SecureCRT和WindTerm两个SSH客户端工具,分别介绍如何使用密钥登录。

OpenSSH有两种认证方式:基于口令认证和基于密钥认证。

基于口令的认证相对简单,仅需在SSH客户端登录时输入密码即可。在某些场景,比如登录公司服务器,一般需要我们通过每人的密钥登录。

本文基于我经常使用的SecureCRT和WindTerm两个SSH客户端工具,分别介绍如何使用密钥登录。

OpenSSH Server默认禁止root用户远程登录,实际工作中我们为了方便使用root账户,通常修改OpenSSH Server的配置文件,以使得root用户可以通过WindTerm或者SecrueCRT等软件登录服务器。

上文我们描述了基于源代码编译安装OpenSSH的方法,本文使用apt安装OpenSSH,并介绍OpenSSH的启动管理方法。

OpenSSH是SSH(Secure SHell)协议的免费开源实现,SSH协议族可以用来进行远程控制, 或在计算机之间传送文件。OpenSSH是用于远程登录、命令执行以及文件传输的SSH协议的完整实现,它支持SSH协议的V1.3、V1.5和V2。自OpenSSH-V2.9 以来,默认的SSH协议是V2,使用RSA 钥匙。OpenSSH提供了服务端后台程序和客户端工具,用来加密远程控制和文件传输过程中的数据,并由此来代替原来的类似服务。

程序主要包括了几个部分:

  • ssh - rlogin与Telnet的替代方案。
  • scp、sftp - rcp的替代方案,将文件复制到其他电脑上。
  • sshd - SSH服务器。
  • ssh-keygen - 产生RSA或DSA密钥,用来认证用。
  • ssh-agent、ssh-add - 帮助用户不需要每次都要输入密钥密码的工具。
  • ssh-keyscan - 扫描一群机器,并记录其公钥。

在Centos、Ubuntu或者Debian等发行版上,我们可以使用yum或者apt提供的软件源直接安装。本文主要讲解的是使用源代码+手工编译+手工安装的方式来编译安装OpenSSH。

上文 supervisor基本使用方法教程 ,我们重点了supervisor的基本使用方法,并未对它进行过多的展开。我们知道supervisor有三个重要的部分 supervisord、supervisorctl、inet_http_server 组成,但我认为隐藏在三部分后面的配置文件,才需要重点关注和学习,毕竟它控制着所有的表现属性。为了比较好的掌握supervisor的使用,本文我们对supervisor的配置文件进行重点分析。

Supervisor is a client/server system that allows its users to monitor and control a number of processes on UNIX-like operating systems.

Supervisor是一个在类UNIX系统上,监控控制大量进程的客户端/服务端系统。其主要功能包括程序自动启动、程序奔溃后自动重启,指定进程数目等等。本文是Supervisor安装、配置和使用的简单教程。

在Linux先编译软件基本都是采用configure文件生成makefile,或者,cmake生成makefile文件两种方式。它们生成的makefile文件,一般默认不支持-g调试选项。

但我们使用这种方式编译出来的静态库时,如果程序运行中core在静态库中,我们看不到有用的相关信息。所以有必要编译出debug版本。

glibc是标准C库的GNU实现。我们采用C/C++所写的程序,运行时基本都依赖与它。如果我们想看当前机器glibc的源代码,首先需要知道当前机器glibc的版本号,然后到glibc的官网下载对应版本的源代码。

目前现代c++的主要标准有c++11/14/17/20/23,我经常使用Debian/Ubuntu的不同版本,有时候想知道当前g++默认c++标准。本文就是记录下查看标准的两种方法。

背景

当前的工作与SVN有关,今天使用SVN库编写了一个小程序,编译代码时发现编译器告警:“warning: ‘svn_client_ls2’ is deprecated (declared at /home/svn/apps/svn/include/subversion-1/svn_client.h:4942)"。

1
2
3
4
5
6
7
svn@linux-rwdx:~/objs/motadou> make
g++ webdav.cpp -o webdav -I/home/svn/apps/svn/include/subversion-1 -I/home/svn/apps/neon/include/neon -I/home/svn/apps/apr-util/include/apr-1 -I/home/svn/apps/apr/include/apr-1 -I/home/svn/apps/sqlite/include -I/home/svn/apps/ssl/include/openssl\
-L/home/svn/apps/svn/lib -lsvn_client-1 -lsvn_wc-1 -lsvn_fs-1 -lsvn_fs_fs-1 -lsvn_fs_util-1 -lsvn_ra-1 -lsvn_ra_neon-1 -lsvn_ra_local-1 -lsvn_repos-1 -lsvn_delta-1 -lsvn_diff-1 -lsvn_subr-1  -L/home/svn/apps/neon/lib -lneon -L/home/svn/apps/apr-util/lib -laprutil-1 -L/home/svn/apps/apr/lib -lapr-1 -pthread /home/svn/apps/sqlite/lib/libsqlite3.a -L/home/svn/apps/ssl/lib -lssl -lcrypto -lz

webdav.cpp: In function 'int svn_list(Handle&, const std::string&)':
webdav.cpp:120: warning: 'svn_client_ls2' is deprecated (declared at /home/svn/apps/svn/include/subversion-1/svn_client.h:4942)
webdav.cpp:120: warning: 'svn_client_ls2' is deprecated (declared at /home/svn/apps/svn/include/subversion-1/svn_client.h:4942)

背景

相比于静态链接库,Linux上的动态链接库和可执行程序都是ELF格式。原理上动态库也能和可执行程序一样直接运行。

比如,可以直接运行“/lib64/ld-linux-x86-64.so.2”,还有“/lib/x86_64-linux-gnu/libpthread.so.0”, 还有“/lib/x86_64-linux-gnu/libc.so.6”等等。举个例子,libc.so.6是C/C++运行时库的GNU实现,我们直接运行该动态库,打印如下信息:

可见,动态库直接运行后,提示了该动态库的编译信息、版本信息等等。在实际项目中,我们也可以为动态库增加类似功能,用户直接运行我们提供的动态库之后,我们就打印该库的编译环境、运行方法、编译版本等等信息,或者完成其他功能。

昨天看一篇关于libco的博文,里面提到了一个由于全静态链接导致的bug。全静态链接?以前没有接触过这个概念,特意到网上搜了下,原来是一个程序将其依赖的所有动态库都替换成对应静态库,即使是libc.so,libm.so,libstdc++.so这种系统级别的动态库。全静态链接出来的可执行程序,不依赖任何动态库,拷贝到任何一台机器,只需要操作系统,这个程序就可以run起来。

这种全静态链接的方式,肯定有好有坏。

  • 第一,缺点:浪费了磁盘空间。全静态链接出来的可执行程序要比动态链接的大。但目前磁盘普遍够大,这个缺点基本可以忽略。
  • 第二,缺点:浪费了内存空间。我们知道相同的动态库在内存中只存在一份,被多个程序共享。而静态库,是需要全部加载到内存的。所以多多少少要浪费一些内存空间。目前来看,内存仍然是服务器中宝贵的资源,能省一些肯定划算。
  • 第三,优点:屏蔽了动态库的版本差异。由于静态链接把所有依赖的函数,全部打包进可执行程序,不依赖于特定机器的动态库函数版本。所有分布式部署的程序,其行为一致。

那全静态链接如何优雅的实现呢?gcc为我们提供了(-static)、(-Wl,-Bstatic)、(-Wl,-Bdynamic),这么几个选项。

重启VMWare虚拟机中的操作系统,会在极端时间内重启完成,无法选择从诸如CD-ROM的其他介质启动,所以就不方便使用当前已创建的虚拟磁盘,来重新安装操作系统。本文记录如何利用已创建的磁盘来重装系统。

我在Github上有多个账号:

  • motadou账号,是主力账号,主要用于fork比较重要的仓库,用于自己存档,该仓库比较杂乱。
  • pagepaper账号,是博客账号,主要用于博文撰写以及gitbook总结性文章,是自己写作的主要基地。
  • mancodenet账号,是代码账号,主要用于存放自己的开源代码,以简练为主。

按照平时的使用习惯,每个账号我都会设置SSH keys进行免密登录。本文就是记录一种可以在同一台电脑上同时使用多个Github账号的方法。

清除全局账号信息

如果之前你设置过全局user.name和user.email,必须先清理掉该全局设置。

也就是说,不能使用全局的user.name和user.email,必须每个仓库设置自己本地的user.name和user.email。

清理方法如下:

1
2
$ git config --global --unset user.name
$ git config --global --unset user.email

使用虚拟机安装Debian,图形界面太耗资源,也用得比较少,所以还是以命令行界面启动比较好。如下是Debian12.10的设置方式。

Ubuntu通过netplan来配置网卡,为了研究netplan的使用方法和实现原理,我们首先通过编译安装的方法,重新定制netplan。

本文记录编译netplan的方法。