【GSL 系列 2】为什么需要 gsl::narrow_cast?

问题

  • gsl::narrow_cast 不就是 static_cast 吗?为啥要用 gsl::narrow_cast?

分析

gsl::narrow_cast 的注释写着:

// narrow_cast(): a searchable way to do narrowing casts of values

其实已经很直白。用它的好处就是——以后要搜索将更容易!那么问题转变为:为什么要搜索?当然是因为将数据变窄是可能有潜在问题的!

下面的例子里,有 gsl::narrow_cast 把数据转窄,又有 static_cast 把数据转宽。如果只用 static_cast,那么在排查哪里把数据丢失时,需要将第二个无关的 static_cast 也查一遍,这就浪费时间了。

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

#include <gsl/gsl>

int main()
{
int i = 0xff;
auto b = gsl::narrow_cast<std::uint8_t>(i);

// std::cout << b;
std::cout << static_cast<int>(b);
}

总之,使用 gsl::narrow_cast 是为了写出更健壮更好维护的代码。

更多

还有一个 gsl::narrow,会在转换丢失数据时抛出 gsl::narrowing_error 异常,适合在不允许数据丢失的场景使用。

八哥之神后传【3】

1988 年,中阴界

圣小开:为什么人间有这么多八哥?为什么我不断转世,不断重复?

巫咸:吾这么天才,创造的国家如此安居乐业,为什么要被灭国?吾还要多纳几个妾!

纣王:寡人是无神论,破除迷信,为什么要被陷害毁谤?寡人还要生三胎!

嬴政:朕勤政务实,统一六国,是王里的学霸,为什么要英年早逝?朕还要批阅更多奏折!

圣小开:哇!原来不甘心死的人跨越时间的联动,就能使得识界诞生?这也太扯了吧!

资本得不到满足,天堂容不下真相,地狱管不住狂傲,人间止不住内卷。识界因我而诞生,精神意识界。

猪头:喂!你瞎唠叨啥?资本都出来了……这里是中阴界,没有资本主义!

圣小开:咦?不是牛头马面吗?为什么是猪头狗面?

狗面:一个文明最大的悲哀就是数学不够发达就明白量子力学,地球文明已经败了,狗只是在观测你们走向灭亡。旺!

圣小开:好有道理,稣居然忘记刚刚问了啥!

猪头:你是怎么死的?

圣小开:稣怎么知道,如果知道也就不会死了!难道是穷死的?

猪头:想不起来就下油锅!赶紧好好想清楚。

圣小开:吓醒!稣点煤油灯看书,大概是一氧化碳中毒。

狗面:小问题,还死不了。你赶紧醒,去户外深呼吸。

圣小开:还能复活?你们说的能算数?

猪头:怎么这么多废话?你根本就没死。回去吧!

圣小开:那我真跑了哦!

狗面:耶,他是不是跑错路了?那个方向是去识界……

猪头:他刚刚好像就是从识界过来的!

狗面:真是千年一遇的人才!但是万一他在识界流连忘返,可就错过自救时机,过一会儿真得死。

猪头:真是可惜!

1988 年,识界

圣小开:稣才六岁怎么能就这么死了?呼,跑到这里应该安全了吧!

黄金灯:开,你来了。

圣小开:你是黄金灯?咦,稣怎么会知道你的名字?

黄金灯:没错!《人脑研究手札》,作者黄清慈的孙子——黄金灯。识界是一个整体,大家互相观测。

圣小开:你爷爷为什么这么牛逼?

黄金灯:他曾经是虎纠婴儿塔的守夜人,研究人脑只是业余爱好。我才是专业的。

圣小开:害怕……你要研究稣的……

黄金灯:人生。

圣小开:哦,吓死!稣的人生,那不怕,研究吧。

黄金灯:哈哈。那你还是先回人间吧。咱们来日方长。

圣小开:稣以后还能来?别吓稣了!

黄金灯:好好做梦就能来。

八哥之神后传【2】

1988 年,乾坤村古宅

太阳一下山,破屋子就乌漆墨黑,只能点煤油灯看书。咳,真难闻,鼻腔又黑了。但是这些书太有意思了,稣一定要早点看完它们。

尤其是这本奇怪的书,只有一开始有奇怪的文字,后面都是鬼画符。

咳!古代的世界太危险了,居然有食人族!不行,稣要惩罚他们!设计一种专门消灭他们的东西吧。哦?原来还真有种蛋白质叫朊病毒,有稣想要的功能。那就丢回古代吧!赫赫。

还有这个故事也太阴暗了,货车撞倒人,发现没撞死要赔钱,干脆倒回去压死他……不行,稣要诅咒这些没良心的人,呃,不够,稣要让所有路口都装上监控,防止这些人作恶没被观测。稣还要安排些大佬推动手机平民化,让大家随时随地可以求助。

最惨的就是这个命案,一个美女被割喉,死前居然没怎么反抗,仿佛就想早点投胎。稣要怎么设计,才能保护美女不被残害?就让社会主义快速发展吧!共产主义早日实现。

咦!房梁上面的老鼠、房梁里面的蛀虫真吵,房梁不会哪天被它们啃断了把稣压死吧!贫穷真危险,但是稣不能给自己安排富人的身份。嗯……那就安排稣的未来的老婆是富婆吧!这样显得稣还是淡然的。

是非是,否非否,量子纠缠叠加态。量子力学和未来一样难以捉摸,好像是稣影响的未来,又好像和稣无关。

等稣看完这本《天才书》就可以明白这一切是怎么回事。

哇!原来这些奇怪的文字是一个叫巫咸的人临死前写的。他说宇宙一直存在两个神人。一个可以通过观测未来而影响未来,一个可以通过观测过去而影响过去。观测未来的人在过去,观测过去的人在未来。宇宙正是因为他们互相观测才会存在……

很玄幻,很扯淡,但可能这才是宇宙的真相!可是,这两个人叫啥?没说。果然是扯淡吗!

还有这些鬼画符!原来是《山海经》。这些鱼画得真恐怖,稣要有童年阴影了!去找表哥借一本现代版来看就好了。

这段文字可真奇怪!

有鱼偏枯,名曰鱼妇。颛顼死即复苏。风道北来,天及大水泉,蛇乃化为鱼,是为鱼妇。颛顼死即复苏

究竟是鱼妇复苏,还是颛顼复苏?难道死人还能原地复活?稣怎么会相信这么无稽的翻译?算了,再自己翻译一段巫咸预言吧!

这里居然留了一个空白,是让读者把自己的名字写上去!赫赫,稣岂能暴露自己的大名?写上“姬稣”吧!稣写!从此以后,稣就是稣。

啊!姬稣将成为无尽轮回的主角之一,也就是在未来观测过去的人。那另一个人呢?什么!就是巫咸!

还好,稣没写自己的真名,赫赫。咦,稣怎么流鼻血了?淡定!淡定!这些鬼故事都不关稣的事,稣是无神主义者。

呼吸越来越弱了,稣得赶紧找找有没有长生术!这里说,彭祖被死神遗忘,活了 888 岁,后来连死神都找不到他。有一天死神化身为一女子,每天在河边用墨条当肥皂洗衣服。彭祖知道后特地来劝她,说:“小姑娘别逗了,我彭祖活了八百多岁,从来没有听说过墨条可以把衣服洗干净,快点去买块肥皂吧!”

死神随即现身,呵呵冷笑,彭祖卒。

赫赫,秀优越感死得快!还是要像稣一样低调才能活得久。但是……怎么才能让死神遗忘?这坑稣的书,总是不说重点!吃点墨?试试!

赫赫,果然没用。现在不止鼻子黑,连手和嘴也黑了。换一本!《人脑研究手札》,作者黄清慈。卧槽,更吓人!这人居然亲自解剖了六百多个脑……究竟是何方神圣?

赫赫,来不及了,下辈子记得攒钱买台制氧机……人死如灯灭,也没啥大不了,稣要淡然地死去。

死神随即现身,呵呵冷笑,稣亦卒。

【GSL 系列 1】为什么有智能指针还要 gsl::final_action?

故事

稣看到一些代码使用手动方式管理资源,便打算安利《Boost【2】ScopeExit》减少心智负担,然而并非所有团队都能立刻接受 Boost 这么大的开发库,于是先推荐 GSL

结果被问了这么一个问题:

  • 用智能指针不行吗?

案例分析

1. 手动管理

假设有一种资源由 C 代码管理,还有一个可能抛出异常的函数,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
extern "C" {

#include <stdio.h>

void init() {
printf("%s\n", __func__);
}

void uninit() {
printf("%s\n", __func__);
}

}

void something_may_throw() {
std::cout << __func__ << '\n';
throw std::exception("Bad news!");
}

那么手动管理的代码可能类似这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void scope1() {
std::cout << __func__ << '\n';

try {
init();
something_may_throw();
uninit();// may leak
}
catch (std::exception& ex) {
std::cout << ex.what() << '\n';
}

std::cout << '\n';
}

它的实际运行结果将是:

1
2
3
4
scope1
init
something_may_throw
Bad news!

八哥在于 uninit 漏调用了!结论:手动管理是有心智负担的!

2. 使用智能指针

利用自定义智能指针的 deleter 来实现自动调用 uninit:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void scope2() {
std::cout << __func__ << '\n';

try {
init();
std::shared_ptr<void> _(nullptr, [](void* p) -> void { uninit(); });
something_may_throw();
}
catch (std::exception& ex) {
std::cout << ex.what() << '\n';
}

std::cout << '\n';
}

运行结果:没有资源泄漏!

1
2
3
4
5
scope2
init
something_may_throw
uninit
Bad news!

但它有两个问题:

  • 丑!

  • 抽象代价高!

使用 Compiler Explorer 查看以上智能指针编译出来的汇编行数,就知道有多污染眼睛!

另外提醒,以下 unique_ptr 版本无法达到效果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void scope2u() {
std::cout << __func__ << '\n';

try {
init();
// nullptr 使 deleter 不被调用
std::unique_ptr<void, void(*)(void* p)> _(nullptr, [](void* p) -> void { uninit(); });
something_may_throw();
}
catch (std::exception& ex) {
std::cout << ex.what() << '\n';
}

std::cout << '\n';
}

3. 使用 gsl::final_action

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void scope3() {
std::cout << __func__ << '\n';

try {
init();
gsl::final_action _{ [] { uninit(); } };
something_may_throw();
}
catch (std::exception& ex) {
std::cout << ex.what() << '\n';
}

std::cout << '\n';
}

运行结果同样完美无泄漏:

1
2
3
4
5
scope3
init
something_may_throw
uninit
Bad news!

并且可读性更好,其对应的汇编也更为简洁。

结论

C++ 是追求尽量降低抽象成本的,显然在这种场景下使用智能指针不如 Boost.ScopeExit 或 gsl::final_action 合适。

八哥之神后传【1】

“稣,果然又活了!赫赫!”

咦?不对劲呢!为啥稣投胎成一条狗?而且,还是母狗!

em……管它的,刚意识过来还太聪明,等等就傻了,无知便是福,旺旺旺,狗的一生很快就过去了。

量子地狱

周易:开,你怎么又跳楼了?

圣小开:稣哪里是跳楼?明明就是那对夫妻没看好稣,稣是不小心掉下去的。你这腹黑神,居然把稣投成小母狗!陈立姻不是说一般的生物承载不了稣的意识吗?

八哥之神【28】

圣小开:“你说,很久以前,也许在其它星球,会不会稣的意识在一条这样的怪物脑子里?”

陈立姻:“不太可能,你的意识很复杂,这类低等动物很难承载。”

圣小开:“那还好!稣就怕,要是自然产生,下辈子会不会变成屎坑里的虫子,那就太不幸了。”

陈立姻:“这个你可以不用担心,能产生你的意识的生命,一定很高等,也很聪明。”

周易:啊嘿嘿。宇宙是随机的,世事难料,怪我咯?

圣小开:那你快给稣一个理由吧,拜托!究竟是什么八哥?

周易:狗血剧是这样滴——

有一天,孟长歌问谷绵:“你打算怎么培养咱们的孩子?”

谷绵回答:“不用特别培养呀,我打算给祂一个快乐的童年。”

孟长歌认为教育理念不合,心灰意冷,于是决定丁克。

圣小开:所以他们养了条狗?还当它是女儿?

周易:耶咦,你太聪明了。

圣小开:谁敢比稣惨呐!不行,这次稣得自己挑个靠谱的妈。

周易:宇宙是随机的,挑妈不如挑个好时代!

圣小开:也对,但稣实在不想悲天悯人、多愁善感了……

周易:相信我,这是你自己设计的,和哪个人生你无关。

圣小开:宇宙是随机的,稣不会一直这么倒霉吧?

周易:不好意思,你的设定就是一直这样,改不了。

圣小开:难道?

周易:没错!天道之中还有天道,人类妄想追求宇宙终极秘密,却没想到宇宙是个死循环。

圣小开:所以宇宙是局部随机,整体上却是有规律的。

周易:宇宙是一个整体。

圣小开:如果宇宙有外面,那么外面又有外面,所以“天道”干脆设计为没有外面。所以它必然有不变的规律。

周易:是的,包括你改变不了自己的设定。

圣小开:吓醒。虽然你讲的全是忽悠,但稣感觉有被安慰到哦!但是,稣还有个机密问题。

周易:问吧,我又不一定会答。

圣小开:天道里能庞加莱重现吗?

周易:其实就是你阻止了庞加莱重现,你死了,天道才能庞加莱重现。

圣小开:哦哦,不知道是不是你随便编的,但这么说显得稣很重要。

周易:还有,只有你死了,神才能出现。

圣小开:稣一思考就悟透轮回。

周易:然并卵,赶紧投胎去。

圣小开:显然稣已经知道自己很重要,可以自己选择父母。

周易:不!你不能。

圣小开:那你帮稣投个天才吧?

周易:这可以。

诗盗·闲卷齐吓传

《#诗盗#·闲卷齐吓传》:呆萌冷对千呼己,八哥吓醒溜大吉。背锅可以要加钱,通宵吸氧啉沟逼。

注解

啉沟逼:闽南语,喝咖啡。

很久很久以前,程序员工资都很低,所以他们经常以听不懂需求为由,要求产品经理多干活,从而把开发周期拉长,顺便气气产品经理。

但是有个程序员是真呆萌,他总是反应迟钝,冷淡面对别人一千次呼唤自己。如果出了八哥,就赶紧吓醒,有危险就溜之大吉。

想让程序员背锅?也不是不行,就是得加钱。只要待遇给到位,可以通宵加班,还自备吸氧机和咖啡。

诗盗·散居

因生问稣股来意,稣话解套不记年。

草履只栽三个耳,麻衣曾补两番肩。

东仓每见西仓血,下车常取上车钱。

半数股民消散后,一根阳柱拉上天。

注解

改编自宋代灵澄禅师的禅诗《山居》:

因僧问我西来意,我话山居不记年。

草履只栽三个耳,麻衣曾补两番肩。

东庵每见西庵雪,下涧常流上涧泉。

半夜白云消散后,一轮明月到床前。

华为擎云 L410

用户故事

上个月写的《用华为擎云 L420 体验国产操作系统(UOS 和银河麒麟)》导致本博客流量暴增,从默默无闻到有人访问,实在太荣幸了……

其实当时稣几乎是同时买 L410 和 L420 的,但由于 L410 的 UFS 是板载的,所以没怎么折腾,而是拿来日常使用,所以反而没写它。现在就来补一补。

先说结论:如果要买量产版的 L410 或 L420,建议后者。

  1. 肉眼可感知 L420 比 L410 快;

  2. L410 板载 UFS,而 L420 可更换,所以 L410 坏了更不好办;

  3. L420 做工更好,尤其是触摸板可以明显感知。(这点可能是个例)

补充:某鱼兼某论坛大佬说,L410 和 L420 触摸板是一样的。但稣手里的 L410 触控板确实八哥比较大,按下去比较松垮,所以这里定义为个例,仅供参考。

如果是买便宜很多的工程机,那务必小心咨询 BIOS 和 EC(Firmware)版本,太低的很可能无法升级,就只能一直忍受 bug 状态。

硬件环境

华为擎云 L410 工程机,型号是 KLVU-WDU0A。

  • BIOS Revision: 1.30
  • Firmware Revision: 1.78
  • hisi Version: 2.0.0.17

由于是打算日常使用的,特地选择 12G 内存+512G 存储的版本。外观比 L420 新,除了 A 面有不明显的小划痕外,没有其它问题。价格也来到惊人的 2000 人民币,真贵……

软件环境

到手时,是个根本不能用的 UOS,要啥啥没有,比如:

  • 指纹解锁——没有!

  • 外接显示器——没有任何反应!

  • 播音乐——wma 无法播放,进度在走,就是没声音……mp4 倒是可以,莫名其妙。

稣自己装上银河麒麟试用版 Desktop-V10-SP1-kirin990-Release-20211228,几乎是可以日常使用,然而只是几乎!八哥如下:

  • 如果没有在开机前就接着电源,那就无法充电。没错,就是开机后,中途想充电,没门!

  • 睡眠或合上盖子屏幕关闭后,屏幕就再也无法亮起,只能重启恢复。不过这时候系统还是正常运行的,外接显示器可以正常使用。由于稣一般都是外接 4K 显示器使用,所以这点倒不是很致命。(多吐槽一句:稣的 L420 至今无法外接显示器!)

  • 麒麟自带的固件升级工具无法使用,一运行就卡着,log 里大量反复的错误。

1
2
3
4
tail -3 /var/log/hwupdate/checkapp.log
[2022-06-18 19:39:13 379]INFO Entery timer
[2022-06-18 19:39:13 417]INFO recv data size is null or fail
[2022-06-18 19:39:13 417]INFO Entry IPCMessageClient::SendData
  • 移动应用无法使用,因为 KMRE 启动不起来。不过稣也用不上这货……毕竟稣有小米平板 5 破落。

总结

这台 L410 的 BIOS 版本不算低,所以八哥没 BIOS 版本过低的 L420 多。

编译 C++ 代码还是挺好用的。尝试编译了一个 gcc13,速度感人,秒杀公司发的联想 L490。而且 512G 版本可以 Clone 好多仓库,所以稣认为性比价还行。

诗盗·蝶恋花·轮回

《#诗盗#·蝶恋花·轮回》

作者:赝稣

建局筹钱难砌路,
两袖清寒,
艳资双飞去。
科技不谙人间苦,
资本到晓造骗术。
昨夜吸风凋敝,
稣独上高楼,
望尽轮回路。
欲寄此生予来世,
宇宙洪荒知何处?

注解

望尽轮回路:稣早就悟透轮回,宇宙是一个整体,每个意识都是同一个意识的不同世,意识可以向过去转世。

欲寄此生予来世:想把今生的记忆传递给来世。(其实也想着想起前世的记忆)

宇宙洪荒知何处:但是宇宙洪荒啊,鬼知道前世是不是条臭虫?算了,还是潇洒走一回吧~

用华为擎云 L420 体验国产操作系统(UOS 和银河麒麟)

用户故事

稣很爱国!从 2019 年起,就不时想用国产操作系统,但基本停留在虚拟机体验的层次,今年终于在物理机长期实践了。

建议

最好别买工程机。如果非要买的话,要同时看准 BIOS 和 EC 的版本。

硬件环境

华为擎云 L420 工程机,型号是 KLVV W5821。

  • BIOS Revision: 0.9
  • Firmware Revision: 0.8
  • hisi Version: 1.0.0.3

某鱼上捡的,外观惨不忍睹,而且就一个主机,配件全无。

到手时,是残缺状态的 UOS 20 1022,基本不能用,只能开机看个寂寞。也是,要不然也不可能 2000 块以内买到……

体验 UOS 20 1041

加了统信两个企业微信群,好不容易要到了一个 iso,然而根本不能启动。稣激动地插入 U 盘,结果它直接黑屏死掉!

机智如稣,立刻想到原来的系统可以启动,把旧系统的内核拿来用不就行了?em,这么干确实成功启动。

之前的系统缺失应用商店等系统组件,装完系统后,总算是一个完整的 UOS 了。然而内核还是旧的,所以……八哥如下:

  1. 内建显示器无法调节亮度,只有关闭和中等亮度两个状态。【稣含着泪,倔强地说道:稣就当服务器用,要什么内建显示器?】

  2. 外接显示器没反应。【稣含着泪,倔强地说道:稣就当服务器用,要什么外接显示器?】

  3. 偶尔开机后没声音。不过注销一下,再登录就能恢复。【稣含着泪,倔强地说道:稣就当服务器用,要什么扬声器?】

  4. 从待机状态恢复后,有小概率内建键盘失灵或内建触摸板控制不了光标。但外接键鼠没问题。【稣含着泪,倔强地说道:稣就当服务器用,要什么键鼠?】

  5. 拔下充电器后,任务栏的电池图标依然一直显示正在充电。

  6. 最可怕的是:开机久了,比如两三周,就有可能无法关机。前兆是同时键盘失灵,这时候关机,并不会真的断电,卡死在一个硬件奇异点,长按开关机键也无用,只能拆后盖断电池排线才能解决。据机友反馈,BIOS 0.11 也有这个问题。

好吧,以上问题都是因为固件的版本太低,只能用充满八哥的低版本内核。只要升级固件,再升级相应的内核就可以解决。但是升级固件这个事太难了……这可是一个奇怪的工程机啊!正规手段都是各种失败,即使是解开固件 deb 包,手动运行 BIOSEC,让它分离出 Firmware.bin 和 Update.txt,也失败!把 Firmware.bin 拿去 BIOS 界面升级固件,依然失败!

BIOS 是百敖 0.09,果然难搞!好吧,没刷成砖头就好。咱们来日方长……【稣含着泪,倔强地说道:学习是终生的,而问题都是一时的!】

接下来说说系统本身的问题:其实 UOS 本身没问题,稣很满意,还是个适配的问题。

L420 的显示服务器是 xwayland,因为其使用的 mali GPU 的用户态驱动是闭源的,只支持 wayland,不支持 x11。这导致部分稣常用的软件无法正常工作,比如远程桌面客户端,em……目前还没发现能用的。【稣含着泪,倔强地说道:稣就当服务器用,要什么客户端?】

体验银河麒麟桌面操作系统 V10

听说银河麒麟更爱国,稣从它的壁纸就可以看出来,这绝对是真的!

银河麒麟桌面

还是熟悉的味道,原版 iso 无法启动,换内核,启动正常,安装也正常。

银河麒麟不愧是上个世纪就诞生的国产操作系统,十分满意,默认设置,只有一个地方稣无法忍受——居然不是默认开启「自然滚动」!而且,图形界面下居然没地方设置?不知道和没激活有没有关系?

银河麒麟-设置-设备-触摸板

但是这对使用 Debian 4 年以上经验的稣来说,简直易如反掌,命令行搞定,注销重新登录生效:

1
gsettings set org.ukui.peripherals-touchpad natural-scroll true

在另一台机器(非 L420)安装银河麒麟后,又发现一个问题比较难以接受:外接显示器的放大比例无法独立设置!

银河麒麟-设置-系统-显示器

任务栏这个风格也不太方便,还是合并到一起好。

银河麒麟-任务栏

另外有一个惊喜,文件管理器借鉴了 macOS 的做法,有个颜色分类功能,很不错!(访达少数满意的地方)

银河麒麟-文件管理器

其他机友关于 BIOS 版本的经验

以下非本人经验,仅供参考,不保证正确性,也不提供相关资助:

  • BIOS 0.11:目前也是升级无望,有机友已经找过华为工程师,结果都搞不定。

  • BIOS 0.18:根据不止一人反馈,是可以升级到 1.x 的。

  • 某鱼兼某论坛上的大佬说任何 BIOS 都是能升级的,但 EC 无法升级。

  • 推测,有些八哥可能来自 EC,所以如果 EC 无法升级,那么即使 BIOS 升级好也无法解决这些八哥,那就只能拆换配件了。