李迟2021年8月知识总结

本文为 2021 年 8 月知识总结。

编码总结

C / C++

产生随机数示例二则。
产生给出范围,并指定数量的随机数。即给定数组(实为向量),其内可预先定义有数值,也可以为空,产生随机数时,需保留原定义的数值(如有),且新的随机数不能与已有的数值相同,已有的值包括原定义的和新产生的。如已有数值 250,则该函数不能再生成 250 这个数。

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
// 产生[a~b)之间 n 个随机数,且随机数不同
// 注:包含a本身,但不包含b,当指定数量 n 大于[a~b)范围时,使用范围值
// result可预先设置一些固定的值,即随机数一定包含那些值
int genRandom(std::vector<int>& result, int a, int b, int n)
{
int total = b - a;
if (n > total) n = total;

int i = 0;
bool found = false;
// 注:使用tmp临时保存,如直接用result,得到的容量会多一些
std::vector<int> tmp;
tmp.resize(n);
srand(time(NULL));
while (1)
{
//公式:a + rand() % n,其中n为整数的范围,a为起始值
tmp[i] = a + rand() % total;
// 将生成的值取已有的值对比,如不同,才保存
found = false;
for (int j = 0; j < (int)result.size(); j++)
{
if (tmp[i] == result[j])
{
found = true;
break;
}
}
if (!found)
{
result.push_back(tmp[i]);
i++;
}
if (i >= n)
{
break;
}
}

return 0;
}

仅产生指定范围内的一个随机数。

1
2
3
4
5
6
7
8
int genRandom(int a, int b)
{
int total = b - a;

srand(time(NULL));

return a + rand() % total;
}

字符串分割示例。
自动去掉字符串前后空格,自动去掉不合法的分隔方式。如:|| 11 |22|33||,原字符串前后分隔符多余,而第字符串有空格。本函数能解析出11、22、33三个有效字符串。

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
std::string& trim(std::string &s)
{
if (s.empty())
{
return s;
}

s.erase(0, s.find_first_not_of(" "));
s.erase(s.find_last_not_of(" ") + 1);
return s;
}
void splitString(std::vector <std::string> &elems, const std::string & s, const std::string & delim)
{
// std::vector < std::string > elems;
size_t pos = 0;
size_t len = s.length();
size_t delim_len = delim.length();

std::string tmp;
if (delim_len == 0)
return;
while (pos < len)
{
int find_pos = s.find(delim, pos);
if (find_pos < 0)
{
tmp = s.substr(pos, len - pos);
tmp = trim(tmp);
if(!tmp.empty()) elems.push_back(tmp);
break;
}
tmp = s.substr(pos, find_pos - pos);
tmp = trim(tmp);
if(!tmp.empty()) elems.push_back(tmp);
pos = find_pos + delim_len;
}
return;
}

自定义打印日志添加 printf 格式检查:

1
void LogInfo(const char * fmt, ...)  __attribute__((format(printf, 1, 2)));

添加后,可以防止LogInfo参数类型不匹配或缺少参数情况的发生。

golang

着手实现转发功能。

delphi

在调试发现提示查询某天日志时,数据库出错。SQL Server 提示[SQL Server]从 varchar 数据类型到 datetime 数据类型的转换产生一个超出范围的值。。oracle 提示ORA-01847: 月份中日的值必须介于 1 和当月最后一日之间。经查,是如下代码出现问题:

1
2
3
4
5
6
7
year:=YearOf(DateTimePicker1.Date);
month:=MonthOfTheYear(DateTimePicker1.Date);
day:=DayOfTheMonth(DateTimePicker1.Date);
datastr:=format('%.4d-',[year])+format('%.2d-',[month])+format('%.2d',[day]);

datastr1:=format('%.4d-',[year])+format('%.2d-',[month])+format('%.2d',[day-1]);
datastr2:=format('%.4d-',[year])+format('%.2d-',[month])+format('%.2d',[day+1]);

代码片段先获取当前日期的年、月、日数值,再通过将算术加减计算前一天和后一天,并组装成字符串。当在月初1号或月尾30(或31)时,就出现问题,此时当前日期、前一天、后一天这三个日期值为:

1
2
2021-08-01 2021-08-00 2021-08-02  
2021-08-31 2021-08-30 2021-08-32

可以看到出现了0032的非法值。日期不能直接用算术的方式加减。而是使用 TDateTime 类型的变量进行加减。如下:

var tdate, tdate1, tdate2: TDateTime;

    tdate := DateTimePicker1.DateTime;
    tdate1 := tdate-1;
    tdate2 := tdate+1;
    
    // 调用YearOf MonthOfTheYear DayOfTheMonth 函数

编码其它

本月对 delphi 工程进行了一次维护,效率较低且无甚好解决方案。一是必须在虚拟机 xp 中使用固定 IDE 进行界面编辑和工程编译;二是 xp 的 IDE 不好用;三是资料较少(年代久远);四是工程大部分用法为旧式,一时难以理解;五是历经廿载的积累及若干代工程师的维护,在搜索代码时,不时能看到1998、2008、2016、2019字样,一种厚重的历史感扑面而来。在前辈面前不敢造次,改代码时战战兢兢,生怕行差踏错。由于其有较高的使用价值,因此依然要学习并掌握。

一般知识

研发思考

继续搞 CMMI 5,着重数据,有很多数据还没理解,根据模板填,不知含义。文档工作量比编码还大。

本月学习及计划

没有集中学习。计划抽时间搞一下请求转发方面的东西。

其它点滴

休息严重不足。
为了开收入证明,跑了 2 趟集团总部,从南宁东南方向到西北方向,单程1小时间。均为中午时分跑。
为评职称,到前前前前单位盖章,单程耗时50分钟。到当前外包单位盖章,单程耗时30分钟。