概述

在编程过程中,一些特殊的时候,我们需要向一个函数传递另一个函数的地址(比如在快速排序中,我们需要传入两个元素大小比较的函数的地址),此时在C语言中一般是通过传递一个函数指针来实现。最近在看《STL源码剖析》一书,上面提到,在C++中其实可以通过另一种方式实现,那就是函数调用操作符() 。本文首先介绍一下C语言中函数指针的用法,然后再介绍C++中函数调用操作符的用法。

C语言中的函数指针

我们先直接看一个例子吧。这个例子比较全面而且简单,其中的函数指针是带参数且有返回值的函数指针,而且还有把函数指针作为参数来传递的代码。这个例子来自 jobbole伯乐在线,代码如下:

概述

Robert C.SearcordThe Cert C Secure Coding Standard 一书中,关于宏定义的规范中第一条就是

用内联函数或静态函数替代与函数相似的宏

这个规范非常实用。内联函数是C99标准中新增的,当宏定义和内联函数可以互换时,应该优先考虑选择内联函数,这也是为什么在C++标准库函数中 max, min, swap 等都是通过内联函数来实现的原因。 宏定义是完全原封不动的很SB的替换,而内联函数则并非简单的文本替换,而是按函数调用的方式展开。关于内联函数相对于宏替换的优点,在wiki有如下几点的总结:

  • 宏调用并不执行类型检查,甚至连正常参数也不检查,但是函数调用却要检查。
  • C语言的宏使用的是文本替换,可能导致无法预料的后果,因为需要重新计算参数和操作顺序。
  • 在宏中的编译错误很难发现,因为它们引用的是扩展的代码,而不是程序员键入的。
  • 许多结构体使用宏或者使用不同的语法来表达很难理解。内联函数使用与普通函数相同的语言,可以随意的内联和不内联。
  • 内联代码的调试信息通常比扩展的宏代码更有用。

其中前面两条很好理解,相信大家应该不陌生,这里主要通过具体讨论一个该书中提到的一个程序实例来感受一下后面几点。

1.概述

C++ 程序的存储空间可以分为静态/全局存储区、栈区和堆区。下图展示了一个典型的Linux C/C++ 程序内存空间布局:

其中,每一部分的具体涵义如下:
- 代码段(.text):这里存放的是CPU要执行的指令。代码段是可共享的,相同的代码在内存中只会有一个拷贝,同时这个段是只读的,防止程序由于错误而修改自身的指令。
- 初始化数据段(.data):这里存放的是程序中需要明确赋初始值的变量,例如位于所有函数之外的全局变量:int val=100; 。 需要强调的是,以上两段都是位于程序的可执行文件中,内核在调用 exec 函数启动该程序时从源程序文件中读入。
- 未初始化数据段(.bss):位于这一段中的数据,内核在执行该程序前,将其初始化为0或者null。例如出现在任何函数之外的全局变量:int sum;
- 堆(Heap):这个段用于在程序中进行动态内存申请,例如经常用到的 malloc,new 系列函数就是从这个段中申请内存。
- 栈(Stack):函数中的局部变量以及在函数调用过程中产生的临时变量都保存在此段中。
静态/全局存储区和栈区一般在程序编译阶段决定;而堆区则随着程序的运行而动态变化,每一次程序运行都会有不同的行为,因此动态内存管理对于一个程序在运行过程中占用的内存大小及程序运行性能有非常重要的影响。 本文主要探讨在C++中如何管理动态内存,以及如何使用 C++ 的语言特性来提高动态内存的管理效率,减少错误的发生。

本文首先介绍一下在 Ubuntu 下如何配置 Android NDK 开发环境,然后用一个简单的 hello-jni 项目来介绍 NDK 开发流程,本文的全部代码下载链接:HelloJni.tar.gz,也可以在我的 GitHub 上下载。

1. 简介

什么是 Android NDK 呢? NDK(Native Development Kit) 是一个允许开发者用一些本地语言(C/C++)编写 Android App 的部分功能的工具集。对于一些特定的 App,NDK 非常有利于我们直接使用现成的用 C/C++ 编写的代码库(但对于大多数 App 来说,NDK 是没有必要的)。使用 NDK 进行 C/C++ Android 开发的基本结构和流程如下图(来自shihongzhi博客 ):

在开始之前,这里要提醒大家:NDK 对大多数 App 而言是不会有太多的好处的,在 Android 上使用原生 C/C++ 代码并不会很明显的提升应用的性能,但却增加了你开发应用的复杂度。所以,仅仅在需要使用 NDK 时才使用它 —— 不要因为你更喜欢用 C/C++。典型的 NDK 应用场景是一些 CPU 操作密集而不需要太多内存的场合,如信号处理、物理模拟等等,很多这些处理过程都已经封装到了 Android 系统内部,所以当你不确定是否要使用本地 C/C++ 代码时,先看看你的需求,以及 Android 框架中的 API 是否已经提供你需要的功能。

很长一段时间以来就看到各种基于 Twitter Bootstrap 主题的博客很清爽,而且对 Tag 的归档也做得很赞,于是很想将自己的博客也换成 Bootstrap 的主题,随着看到的博客越来越多,自己的 Octopress 主题先得越来越臃肿,而 Tags 归档功能也相形见绌,更换主题的欲望越来越强烈了。于是乎,趁这个周末捣鼓了一番,最终大功告成,在这里分享一下具体过程。

Bootstrap 主题的安装

首先下载适用于 Octopress 的 Bootstrap主题 并解压缩到博客的 .theme 目录,然后安装:

rake install['bootstrap']

安装的过程中可能会提示有 sass 或其他依赖库的语法错误神马的,这是因为 sass 的版本过低,可以通过如下命令来跟新:

bundle update sass

在Leetcode上有好几道全排列相关的题,一直以来只是会写基于递归的全排列生成算法,遇到这几道题后,搜了下一些非递归的实现方法,发现其实全排列的生成还是很有规律的有木有!这里就总结一下递归和非递归的全排列生成方法,并分析一下 STL 的实现。

递归和非递归实现全排列生成的方法也分别有多种,递归法有基于交换的,有基于链接的,还有回溯,非递归法有排序、回溯、求模等,关于所有这些方法的具体实现参见 全排列的六种算法. 本文只实现一种递归和一种非递归算法,并在最后对 STL 的非递归算法进行分析。

本文的全部代码下载:code.

递归法求全排列

递归法的基本思路是这样的:

首先选一个元素排在第一个(有 n 中选法); 然后递归的对剩下的所有元素进行全排列; 直到一个元素的全排列是其本身。

假设给定的元素序列为 ,其全排列表示为 P(e1, e2, ..., en),则对递归的第一步展开有:

P(e1, e2, ..., en) = { , , ... ... }

引子

在码代码的过程中,不经意间就会遇到需要交换两个变量的情况,一般情况下都是通过新定义一个同类型的变量来中转,但自己也知道可以不用定义新变量直接原地交换,但具体如何原地交换以及其中可能隐藏的bug却了解得不是很清楚,于是乎google了一下,发现这里面还真是有很多学问呢,这里整理和总结一下。

原地交换两个变量,最主要有加减法和异或法。

本文完整代码链接:20140411.cpp

加减法

加减法最简单、最好理解了,设待交换的两个变量分别为 a 和 b ,首先将两者的和赋给 a ;然后将 a 与 b的差赋给 b ,这样 b 就是 a 原来的值了;最后再将 a 与 b 的差赋给 a ,这样 a 就是 b 原来的值了。具体代码如下:

inline template <class T>
void xswap(T &a,T &b){
    a=a+b;
    //printf("a=%u\n",a);
    b=a-b;
    a=a-b;
}

概述

最近在做的一个项目,需要对大量数据进行一些基本的统计和处理,整个程序的思路很简单,但处理起来却很慢,特别是有二重循环的地方,龟速前进,眼看着16核32线程 的服务器只有一个线程被利用,束手无策。之前一直听说Go是一门对并发编程有很好的支持的语言,七牛的许牛大力推崇Go语言,于是就开始了对Go并行编程的探索之旅。

最近这两年推荐系统特别火,本文搜集整理了一些比较好的开源推荐系统,即有轻量级的适用于做研究的SVDFeature、LibMF、LibFM等,也有重量级的适用于工业系统的 Mahout、Oryx、EasyRecd等,供大家参考。PS:这里的top 10仅代表个人观点。

#1.SVDFeature

主页:http://svdfeature.apexlab.org/wiki/Main_Page 语言:C++
一个feature-based协同过滤和排序工具,由上海交大Apex实验室开发,代码质量较高。在KDD Cup 2012中获得第一名,KDD Cup 2011中获得第三名,相关论文 发表在2012的JMLR中,这足以说明它的高大上。
SVDFeature包含一个很灵活的Matrix Factorization推荐框架,能方便的实现SVD、SVD++等方法, 是单模型推荐算法中精度最高的一种。SVDFeature代码精炼,可以用 相对较少的内存实现较大规模的单机版矩阵分解运算。另外含有Logistic regression的model,可以很方便的用来进行ensemble。