时习之

学而时习之,不亦说乎


  • 首页

  • 标签

  • 归档

  • 搜索

浅谈字符字面量的地址

发表于 2018-12-15 | 阅读次数:

在C和C++的世界里,我们允许字面量直接出现在表达式中,常用的字面量分为两种:字符字面量和数字字面量,比如:

1
2
const char* sl = "hello world";
int a = 42;

在上面的例子中,hello world和42都是字面量,因为他们没有任何的变量和它对应,直接以值的形式出现在表达式中。

它们两者虽都是字面量,但是他们两者有一个非常本质的区别,那就是字符字面量有自己的地址而数字字面量没有。个人理解的原因是,C/C++语言中并没有内置字符串这种类型,字符字面量实际上是char这种内置类型的一个序列,我们没有办法原子操作字符串,所有关于它的操作都需要借助指针来完成。在上面这个例子中:int a = 42实际上把42这个值给了a这个变量,而const char* sl = "hello world"则是把"hello world"这个字面量在内存中的地址,给了sl这个指针变量【1】。

那么,同一个字符字面量的值,地址会是一样的吗?也就是说下面这个例子的输出到底是s什么:

1
2
3
4
const char* s1 = "Hello world";
const char* s2 = "Hello world";

std::cout << std::boolapha << (s1 == s2) << std::endl;
阅读全文 »

捉妖记之——状态机模式

发表于 2018-12-09 | 阅读次数:

状态机是一种非常好的表达逻辑跳转的方式,但是本身容易导致代码的耦合,维护性不佳。状态机模式是状态机结合面向对象之后的产物,既保持了状态机,清晰的逻辑表达能力,又加入了面向对象的高内聚性和可扩展性,提升代码的可维护性,是我非常喜欢的一种设计模式。

最近碰到一个问题,比较适合用状态机来描述,果断的使用了状态机模式,但是编写代码的过程中出现了一个隐藏很深的BUG。

阅读全文 »

捉妖记之——私有继承

发表于 2018-12-09 | 阅读次数:

C++的继承和大部分的语言不同的地方在于它的继承也有访问权限。通常来说用得比较广泛的两种是,公有继承和私有继承。虽然他们都是继承,但是实际上有非常本质的区别。《Effctive C++》中有提到,私有继承实际上是has-a的关系,而公有继承才是真正传统意义上的继承,也就是is-a的关系。

阅读全文 »

C++静态检查工具总结

发表于 2018-11-24 | 阅读次数:

最近在尝试做代码审查,发现很多时候我们把时间花在了低级的规范性错误上面,为了节省这一部分的时间,我尝试了各种静态检查工具,这里做个简单的汇总,方便日后的查看。

阅读全文 »

如何阅读代码

发表于 2018-10-21 | 阅读次数:

写这篇文章之前,我脑海中实际上想总结的内容是如何快速的定位到一个别人项目中的BUG。就个人经验来说:找自己代码中的BUG,要比找别人代码中的BUG简单;找目前在维护的代码的BUG,比找半年以前写的代码的BUG容易。这些现象的背后揭示的道理是,一段代码,你理解的越是透彻,你能找出其中的问题的概率越大。所以在谈怎么样快速定位到一个BUG之前,想先聊聊怎么样去读懂别人写的代码。

阅读全文 »

读左传——郑

发表于 2018-09-23 | 阅读次数:

郑庄公

说起春秋的霸业,通常人们会说齐桓晋文,因为他们两个是春秋时期最显赫的霸主。实际上 在齐桓公称霸之前,郑庄公也曾经小霸诸侯。

郑庄公,名寤生,现在很难判断寤生这个词的含义,但是可以肯定的是他的出生让他母亲 武姜很不舒服,所以他母亲喜欢他弟弟共叔段不喜欢他。左传里面的第一个长篇故事《郑伯 克段于鄢》,说的是郑庄公如何打败他弟弟的故事。共叔段在他母亲的帮助,一步一步的走 向夺权篡位之路,庄公一开始就知道,但是没有采取任何行动,直到共叔段真的要篡位的时 候,一举把他干掉。有人说庄公非常的腹黑,把弟弟养肥了杀掉,不断纵容他作恶,直到他 走上谋反之路。也有人从这段故事中读到了一个不断想要在母亲面前证明自己的不被宠爱的 孩子的满腔委屈。庄公大概极度愤慨,才会在干掉共叔段之后对母亲说出:不及黄泉无相 见这样的狠话。但是他终究还是爱自己母亲的,所以话刚说完就后悔了,最终引出了颍考 叔那个掘地及泉隧而相见的妙计。

郑庄公和他父亲郑武公都是周王的卿士,平王东迁,靠的是晋国和郑国的力量,庄公能够小 霸一定意义上来说靠的就是这种优势。可惜这张王牌他没有打好,他做的事情有点挟天子以 令诸侯,比如他以王师虢师伐卫,又以虢师伐宋,很明显用公家资源办私事儿。周天子不爽 他(可能和上面这种行为有关),所以想把政权给虢公,庄公为了这件事情和周天子交换了 人质。但最后周天子还是把政权分给了虢公,郑庄公就派人把天子的麦子割了。君子说 信 不由衷,质无益也,明恕行之,要之以理,虽无有质,谁能间之。周郑的关系不断恶化, 最后两国交战,郑祝聃射王中肩。

郑庄公能够崛起,很大程度上靠的是他强大的武力,他不断的和宋、卫、陈、蔡、周、戎交 战,武力上基本上可以碾压这些国家。郑国在战术上可以说是先驱,左传记载了他们和戎人 、周人交战时使用的战术,都非常的精妙。

晚年的庄公似乎比年轻的时候温和很多,他不在单打独斗,和齐国、鲁国结成了同盟。伐许 而入却没有占领他们的土地,感叹周室衰微,有种英雄落幕的感觉。

庄公最大的失败估计在于他对后世没有很好的安排,他的儿子其实都很能干,太子忽其实算 一个比较厉害的角色,可惜遇到子突这么能干的弟弟。庄公死后郑国内乱,从此也就迅速的 衰落下去了。

Linux开发者的Windows生存指南

发表于 2018-09-15 | 阅读次数:

平常习惯了linux的zsh+tmux+vim组合,开发体验非常完美,最近应该工作需求不得不 在 Windows上做大量的开发,简直就是煎熬。花了一点时间折腾,最终用 nvim+powershell 的方式勉强支撑起Windows下的开发。这篇文章总结了我尝试过的各 种方式,谈谈我对这几种方式的优缺点的看法。

阅读全文 »

读左传——鲁

发表于 2018-09-09 | 阅读次数:

鲁隐公

隐公可以算是一个悲情角色了,他的为人是很正派的,他因为摄政称王春秋不书继位,被弑 而亡春秋不书葬,幸亏有左传的存在,让我们可以看到这背后的辛酸。

隐公的悲剧说到底都是他父亲惠公(这种德行也能谥号称惠,估计有其他过人之处)埋下的 祸根。春秋,国君依礼应该只有一位夫人,惠公夫人孟子(孟是排行老大,子是姓,宋国人 )无子,卒,继室以声子,生隐公。按理隐公是庶长子,正常情况下,惠公去世,隐公会顺 理成章的成为下一任国君。

天意弄人,宋武公生了一个女儿仲子(仲是排行老二),生而有文在手曰:鲁夫人,所以仲 子也要嫁给鲁国。按照史记的说法,仲子本来要嫁给隐公(他本来是下一任国君,所以他的 夫人就成了下一任鲁夫人),但是惠公看仲子长的漂亮,自己把她娶了做下一任夫人,生下 了嫡子:桓公。于是隐公就这样默默的从第一顺位继承人,变成了第二顺位继承人。

鲁桓公出生不久,惠公就去世了,太子太小,隐公摄政称王但奉弟弟为君。有人认为春秋从 隐公开始(春秋来自鲁国的国史,国史不可能从隐公开始,如果春秋是孔子根据鲁史编的, 他选隐公开始,可能是有他的考虑的)是因为隐公这种行为非常像鲁国的始封君周公旦,立 成王,但是自己摄政称王,安定周朝的天下。

隐公其实算得上是一位贤主,他的统治期间,最主要的政策就是和各国讲和,创造一个稳定 的环境。他的统治期间,国家没被打过,跟着郑庄公去打宋国(宋国自己蠢没办法),还得 了几块地。

但是隐公魄力上终究比周公差了点,最明显的差别是,周公摄政称王得以善终,但是隐公没 有。隐公其实一直没把自己当国君,所以他的生母死了,不以夫人礼下葬,但是桓公生母死 了用的是夫人礼(还特意建了新的庙,夫人本来不单独建庙,夫人死了,牌位安放在国君的 庙中,但是鲁惠公庙中已经有了原配夫人孟子的牌位,所以仲子不能以夫人礼放到惠公的庙 中,只能单独建一个庙,可谓煞费苦心),改葬惠公,他也不当主祭,让桓公当主祭,大夫 死了也不参加小歛。

公子翚,当时的权臣,以小人之心猜测隐公其实想自己为王,自愿为隐公杀了桓公,条件是 要封自己为太宰(当时鲁国没有这种官职)。隐公真心想让位,没答应,让公子翚去把自己 养老的城池修好一点。公子翚怕了,反咬隐公一口,在桓公面前说隐公想篡位(桓公大概也 是猪脑子,真想篡位干嘛不在他还小的时候直接干掉他)。桓公就合谋公子翚把隐公杀了, 让寪氏做了替罪羔羊。

这种事情,其实周公也碰到过,他哥哥管叔以为他想篡位,联合纣王之子武庚造反,周公平 叛之后把他哥哥杀了。这种手腕可能听起来很残忍,但是他能做到罚不避亲,真正让人信服 。隐公之死告诉我们很重的一个道理是,对作恶要绝对的零容忍,公子翚这种不君之人,如 果隐公没有放过他,可能他最后真的可以安安心心的去养老,成就一段佳话。

鲁桓公

鲁庄公

C++包管理器——conan

发表于 2018-04-23 | 阅读次数:

C++可以说是社区驱动型语言,它不像Java和Go背后有主导的公司在推,它的发展更多靠的是由各路专家组成的标准委员会。所以一直以来,它饱受诟病的一点是较难统一,虽然有统一的标准,但是不同的组织有不同的实现和扩充,不同的构建方式,不同的包管理工具。

近年来,CMake慢慢的成为了C++项目构建方式的事实标准,而这篇文章要介绍的是个人认为很有可能在未来几年成为C++包管理工具事实标准的:conan。

阅读全文 »

C++轮子——函数式编程

发表于 2018-04-16 | 阅读次数:

和算法配套出现的组件除了迭代器之外还有仿函数,这篇文章会重点介绍仿函数的使用以及和它相关的函数式编程工具。

仿函数

算法库中有很多算法都有一个重载的版本,接收一个Callable object用于提升算法的灵活性。

1
2
3
4
5
6
7
template< class InputIt, class UnaryPredicate >
InputIt find_if( InputIt first, InputIt last,
UnaryPredicate p );

template< class InputIt, class T, class BinaryOperation >
T accumulate( InputIt first, InputIt last, T init,
BinaryOperation op );

语法上可调用对象(Callable object)是指可以使用函数调用符号操作它的任何对象,它可以表示很多对象,比如普通的函数,也比如一个重载了函数调用符的类型对象。如果可调用对象的返回值是bool则称之为Predicate(有人翻译成谓词)。接收Predicate的算法通常都以_if结尾,比如:std::find_if,std::copy_if。

我们把重载了函数调用符的对象称为仿函数,它在功能上是一个函数,在语法上是一个类。它和普通函数最大的区别是它可以保存内部状态。

假如我们现在要找出第一个奇数,我们可以这样写:

1
2
bool is_odd(int a) { return a % 2; }
std::find_if(std::begin(a), std::end(a), is_odd)

假如我们要查找第一个偶数,我们可以写成这样:

1
2
bool is_even(int a) { return !is_odd(a); }
std::find_if(std::begin(a), std::end(a), is_even)

但是如果我实现成仿函数,我们可以这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class FindOdd {
public:
NumberPredicate(bool found_odd) { ... }

bool operator()(int a) const {
if (found_odd_) {
...
}

...
}

private:
bool found_odd_;
};

std::find_if(std::begin(a), std::end(a), FindOdd(true));
std::find_if(std::begin(a), std::end(a), FindOdd(false));

上面这个例子其实并不太恰当,我不推荐在一个函数中实现两个功能,但是它展示了仿函数区别于普通函数的重要特性——可以保存状态。

阅读全文 »
12…11
郭荣飞

郭荣飞

记录成长路上的点点滴滴

108 日志
33 标签
© 2018 郭荣飞
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.4