移动平台native代码遭遇的坑

最近客户端终于开始运行在移动平台上了(当然,快开发完才开始在移动平台尝试运行,本身就是一件很错误的顺序,然而这并不是我所能控制的),之前在PC平台上完全没问题的代码,开始出现一些诡异的问题。 为了保证客户端和服务器使用绝对相同的逻辑执行流程,我们采用C++来开发一部分native代码同时供客户端和服务端来使用。在迁移到移动平台时,这些native库在IOS和Android平台上出现了不同程度的水土不服。 首次在移动平台就发生了crash,并且只有Android平台会crash, 而IOS可以正常……

C程序中让两个不同版本的库共存

今天有同学提出,如何在一个C程序中让两个不同版本的库共存。 首先想到的方案是,把其中一个版本的库函数全部重命名,比如把每一个函数名都加一个_v2的后缀。 人工替换到没什么,但是如果函数个数超过10个,就有点不拿人当人使了。 而使有工具去替换就会遇到一些棘手的问题,如何识别哪些是函数,哪些是系统函数(系统函数不需要添加后缀)等。 随后想到的另一个解决方案是C++的方案,为其中一个版本库中的所有文件添加命名空间。然后使用g++将这部分代码编译成.o文件,之后再使用gcc……

为什么要有头文件

我在写C文件时,一般会首先确定这个模块需要哪些功能,然后在头文件中定义相应的接口函数。之后才是在C文件中实现,在实现过程中除非有遗漏的接口,不然是不会再切回头文件的,一般辅助函数我都是直接以static的方式定义在C文件中。 在写C++代码时,这些代码辅助类的函数,都必需要以private的方式在头文件中声明。这会导致在写代码时,需要频繁在h/cpp之间切换,极度令人不舒服。 因此每次在写C++代码时,都免不了在心里抱怨几句为什么不把private函数直接定义在cpp文件中,或者干……

C++默认构造函数

在C++中,如果不为某个struct/class实现一个构造函数,那么编译器就会自动为这个类添加一个默认构造函数,而这个默认构造函数什么也不干。 但是我却从来不知道,默认构造函数在不同的情况下,会出现不一样的效果(当然这是C++03之后的标准). 先看一段代码: struct test { int a; int b; }; void *operator new(size_t sz) { void *p = malloc(sz); for (size_t i = 0; i < sz; i++) ((char *)p)[i] = 0x01; return p; } int main() { struct test *t1……

迭代器模式

在写C++代码时,首先接触的就是迭代器。甚至于设计模式都有一种模式叫迭代器模式。虽说网上到处都说迭代器用于隐藏数据结构的细节,但我却一直没有真正搞明白为什么需要迭代器去隐藏数据结构细节。 在写C++代码时,一般我每用一个数据结构都会去查一下,他大致是如何实现的(不然用起来不太放心:D)。 因此一般情况下我在c++下都是使用类似类似for(size_t i = 0; i < vector.size(); i++)的方式去遍历vector的每个元素。 直到最近的一次重构我才大概明白什么时候去使用迭代器模式……

模板的高级用法

一直以来都是通过C用基于对象的设计方法来写代码。即使工作中使用C++, 也是尽可能少的使用超出C的一些特性。当然这并不是C++不好,而是C++实在太复杂了。以我的脑力来讲, 如果使用C++过多的特性, 很容易让我过于陷入语法特性之中, 而忽略了设计。因此, 对于C++的一些高级特性, 如模板等并没有深入研究过。 模板对我来讲, 仅限于知道可以实现泛型。至于怎么巧妙的利用泛型来实现其他特性, 从来没有深入研究过。最近工作中,碰到了一些看起来比较高端的模板用法,令人有一种耳……

c语言部分的开销测试

最近在写c代码时底气越来越弱,原因在于某些调用的开销,我心里并不是十分明确。写起代码来由于纠结也就变的畏畏缩缩。 今天终于抽时间测了一下,仅测试了最近常遇到的一些调用的开销。 测试环境如下: CentOS release 6.7(Final) CPU:Intel(R)Xeon(R)CPU E3-1230 V2 @ 3.30GHz 采用gcc(glibc)编译,未开任何优化。 在测试时,大部分操作cache均会命中,因此如果cache经常命中失效,还需要另外考虑。 测试结果如下: 可以看出for循环是最廉价的。 malloc是开销最大的,这……

std::vector的错误使用

上周五服务器线上出现了几次crash,拿回dump文件分析后发现代码是崩在了对一个引用的成员变量赋值上。 分析了半天也没看出来代码有什么不妥,就先搁置了。 今天同事又给我看了一段奇怪的代码,某个类成员函数返回了某个成员变量的引用,但是当指针为NULL时去调这个函数依然不会崩溃。 思来想去搞不明白,反汇编之后终于发现原因所在。 c++引用本质上也是指针,只是不能为NULL而已。因此返回引用其实就是返回这个变量的内存地址。也就是说这个函数实际的操作仅仅是拿this指针加上这个……

bitfield数据类型的坑

bitfield并不具有可移植性,因此实际使用中,我都是尽量使用bitand来代替。 然而代码中之前就已经使用了bitfield的定义方式,作为后续开发我没有理由去改掉这个数据结构(除非它有问题),结果就无意间踩到了这个坑。 bitfield定义和使用大概如下: union utest { int val; struct stest { int a:3; int b:5; }; }; union utest t; t.value = 0x07; bitfield冒号后面的数字标识bitfield的位宽,bitfield前面的类型用于标……

volatile关键字

今天快下班前听到他们正在讨论说某个bug可能是编译器优化导至的bug, 我当时正在忙其他事也就没有参与讨论,下班回来的路上想到了编译器优自然而然就想到了volatile关键字。 随手上百度搜了一下,得到的结论令我大吃一惊,说什么的都有,有说阻止编译器优化,还有说用于多线程并发,还有说影响cpu cache,总之说什么的都有。其他的我不敢说,但是至少编译器级别的优化还达不到cpu cache的层次,毕竟我搞过一段时间的无锁算法的,对cpu的cache原理有一定的了解。 至于真相到底是什么,……