代码改变世界

随笔分类 - C/C++

c库的rand/random随机数产生函数性能差?

2012-06-10 19:17 by zhenjing, 7821 阅读, 收藏, 编辑
摘要:有网文称c标准库的rand/random随机数产生函数性能极差。一直信以为真,但从没做过验证。最近因其他因缘,写了些代码专门验证rand/random的性能。结果大出意料,颠覆之前的成见。 结论如下: 1) rand/random性极佳。在64位机器上,其性能大约比简单自增略低30%(32位的自增比64位性能高出1倍以上)! 2) srand/srandom性能极差极差。绝对不能每次调用rand之前都调用srand。这么做不仅没必要,还会极大降低性能,性能只有调用rand的1%!!! 阅读全文

通用高效的c++内存池(特定类型)

2012-06-03 15:35 by zhenjing, 3689 阅读, 收藏, 编辑
摘要:介绍一最近实现的特定类型的通用高效C++内存池。 特点: 1)基于共享内存; -- 不会因为进程挂掉而丢失数据。 2)快速分配; -- 在内存池接近满时,效率不高。 3)快速回收;-- 常数 4)空间利用率高 -- 利用bit标识内存块使用与否 (《C++设计新思维》的小对象分配器不占用额外空间!!) 阅读全文

工具脚本(网络编码)

2012-05-18 19:56 by zhenjing, 429 阅读, 收藏, 编辑
摘要:自用的工具脚本:1) 生成结构体网络编码(Ntoh(), Hton() )的perl脚本; 2) 正则表达式测试脚本。 阅读全文

RAII、栈展开和程序终止

2011-07-06 00:11 by zhenjing, 2825 阅读, 收藏, 编辑
摘要:RAII(资源获取即初始化RAII, Resource Acquisition Is Initialization)是C++编程中很重要的一项技术。其原理是在对象析构函数中释放该对象获取的资源,利用栈展开过程栈上对象的析构函数将被自动调用的保证,从而正确地释放先前获取的资源。RAII只有在栈展开正常执行的前提下才能正常工作。函数调用和正常的C++异常处理流程(异常处于try-catch块)都存在栈展开。应该特别注意的是:在程序运行过程中,RAII可以可靠地正确地释放资源;但当程序非正常终止时,栈展开经常被忽略,从而导致RAII失效。 阅读全文

Gdb调试多进程程序

2011-06-01 13:45 by zhenjing, 22040 阅读, 收藏, 编辑
摘要:介绍使用gdb调试多进程程序的几种常见办法:方法1:调式多进程最土的办法:attach pid; 方法2: set follow-fork-mode child + main断点; 方法3: set follow-fork-mode child + catch exec; 方法4:info inferiors/inferior inferiors 阅读全文

内存数据的十六进制Print

2011-04-20 09:22 by zhenjing, 2948 阅读, 收藏, 编辑
摘要:在程序的调试过程中,经常需要输出各种数据,正常情况下使用printf和cout即可实现数据输出。然而在输出二进制数据时,printf和out却有点无能为力。那么如何比较二进制数据是否正确呢?方案一:文件输出。文件可以输入任何数据,但是需要在程序之外比较文件,这对于少量数据并不划算。方案二:实现自定义的十六进制输出函数。当然,也可是八进制,一般而言十六进制更易看懂(习惯)。下面给出一个最近实现的此类函数。该函数可将指定长度任何内存数据以十六进制格式输出。这个程序对32和64位的PC均适用。注意:%x无法正确打印负数,负数总是打印成32bit整型数,64位PC也是如此。#include <s 阅读全文

GCC/G++常见链接错误

2011-04-20 09:21 by zhenjing, 719 阅读, 收藏, 编辑
摘要:链接错误的直接表现就是:****符号未定义。几种常见的链接错误如下:缺少*.o文件 ---- 对策:将相应的文件加入Makefile或命令行*.o文件未更新 ---- 对策:删除旧*.o文件重新编译或者依赖于最新的depend来编译(增删文件时确保make depend)。缺少相应的库文件 ---- 对策:将相应的文件加入Makefile或命令行依赖的库文件版本不对或未更新 ---- 对策:重新生成所依赖的库文件库文件的出现顺序不对 ----- 对策:根据库的依赖关系,调整库出现的顺序。原则:只允许先出现的库依赖于后出现的库。其中,第5种错误最难发现。如果发现程序所需的库都已经引入,但仍出现链 阅读全文

[Advance] How to debug a program (下):示例

2011-03-23 13:10 by zhenjing, 960 阅读, 收藏, 编辑
摘要:原理:程序=指令+数据。 指令:用户代码(Text)+静态库+动态库。反汇编可得程序指令。 数据:Data -- 已初始化的全局数据,包括常量字符串;BSS -- 未初始化的全局数据;Heap; Stack;Register 阅读全文

[Advance] How to debug a program (上)

2011-03-22 12:16 by zhenjing, 1900 阅读, 收藏, 编辑
摘要:介绍64位linux系统下的一种高级调试技巧。32位类似,内存分布略有区别。 阅读全文

[转] Real-World Concurrency

2011-03-15 13:37 by zhenjing, 404 阅读, 收藏, 编辑
摘要:1. Know your cold paths from your hot paths. 弄清楚代码里的热门执行路径和冷门执行路径。 2. Intuition is frequently wrong—be data intensive. 直觉常常是错的,要靠数据说话。 3. Know when—and when not—to break up a lock. 知道什么时候把一个锁拆成多个,并知道什么时候不必这样做。 4. Be wary of readers/writer locks. 警惕读写锁。 5. Consider per-CPU locking. 考虑用每个 CPU 用一个锁。 6. Know when to broadcast—and when to signal. 知道什么时候用单个唤醒,什么时候用广播唤醒。 7. Learn to debug postmortem. 学会验尸 8. Design your systems to be composable. 设计系统(s),使之能相互组合。 9. Don’t use a semaphore where a 阅读全文

[转] Policies/Binary Compatibility Issues With C++

2011-03-15 11:11 by zhenjing, 462 阅读, 收藏, 编辑
摘要:C/C++ 的二进制兼容性 (binary compatibility)与ABI (application binary interface)关系甚大。到底如何判断一个改动是不是二进制兼容呢?这跟 C++ 的实现方式直接相关,虽然 C++ 标准没有规定 C++ 的 ABI,但是几乎所有主流平台都有明文或事实上的 ABI 标准。C++ ABI 的主要内容: * 函数参数传递的方式,比如 x86-64 用寄存器来传函数的前 4 个整数参数 * 虚函数的调用方式,通常是 vptr/vtbl 然后用 vtbl[offset] 来调用 * struct 和 class 的内存布局,通过偏移量来访问数据成员 * name mangling * RTTI 和异常处理的实现(以下本文不考虑异常处理) C/C++ 通过头文件暴露出动态库的使用方法,这个“使用方法”主要是给编译器看的,编译器会据此生成二进制代码,然后在运行的时候通过装载器(loader)把可执行文件和动态库绑到一起。如何判断一个改动是不是二进制兼容,主要就是看头文件暴露的这份“使 阅读全文

[转] Buffer Overflows and You (下)

2011-03-03 11:59 by zhenjing, 563 阅读, 收藏, 编辑
摘要:Got root?Gentlemen, we can root it. We have the technology. We have the capability to root yet another poor idiot's server on the int4rw3bs. Steve Austin will be that man. Better than he was before. Better, stronger, faster, errrr...We spent all that time developing a small bit of shellcode. Let 阅读全文

[转] Buffer Overflows and You (上)

2011-03-03 11:48 by zhenjing, 608 阅读, 收藏, 编辑
摘要:Magical gnomes present: Buffer Overflows and You Is it the 90's? Are you wondering why your server is running slow? Why it's trying to ping flood some host in California? Why someone else is logged into your machine and you've recently become a prominent porn hosting provider? This site will help you figure it all out. And if you have a time machine, you can probably go back and do it to someone else! Before continuing, it's important to note that this guide is designed for 64-bit systems. 阅读全文

[C++再学习系列] stl::string与二进制数据

2011-01-30 14:14 by zhenjing, 7377 阅读, 收藏, 编辑
摘要:C99有很多和string相关的函数,如 strcat,strchr,strcmp,strcpy,strlen,strncat,strncmp,strncpy等。然而使用C++编程时,所有和string相关的操作均可以使用string类的相关接口完成,string提供和原来C接口类似的功能和性能,同时提供更高的安全性。 String类有一个特性:a string of length n must manage a block of memory whose size is at least n + 1。即长度为n的string对象,其内存空间至少为n+1个字符,且最后一个字符为’\0’。不过在进行string操作时,有一点必须牢记:C/C++语言的string是以’\0’结尾的,对不以’\0’结尾的string进行操作容易引发错误,甚至导致内存溢出等crash。 C++的string类,除了用于处理常规string操作外,其本身也可用于存储各种数据,如文件数据。使用者采用string( const char* str, size_type 阅读全文

[C++再学习系列] STL容器删除操作总结

2011-01-30 12:01 by zhenjing, 2304 阅读, 收藏, 编辑
摘要:由于容器所对应不同的迭代器、指针和引用的失效规则,使得容器的删除操作较为复杂。解决问题的最好方法取决于你是怎样鉴别出哪个对象是要被去掉的,储存它们的容器的类型,和当你删除它们的时候你还想要做什么。 阅读全文

[C++再学习系列] 函数声明与STL容器构造

2011-01-28 10:56 by zhenjing, 1122 阅读, 收藏, 编辑
摘要:C++有一条通用规则——几乎任何东西都可能被分析成函数声明。如果使用不当,这个规则将引发“声明错误”,将声明被当成函数来解析。这种现象在STL容器的使用中最常见。 阅读全文

[C++再学习系列] 函数模板和类模板

2011-01-25 12:51 by zhenjing, 946 阅读, 收藏, 编辑
摘要:函数模板和类模板C++提供类模板和函数模板。函数模板允许重载,而类模板不允许重载(类无重载概念)。类模板可以进行全特化和偏特化,而函数模板仅能够全特化。因此,写一个看似函数模板偏特化的函数模板实际上是在写一个单独的主函数模板!由于函数模板可以重载,因此存在重载决议。但是记住,函数模板特化并不参与重载。只有在某个主模板函数被重载决议选中的前提下,其特化版本才有可能被使用。因此,如果想要将一个主模板特化,同时希望该特化版本能够参与重载决议,那么应该将使用普通函数而不是特化版本。(这是因为普通函数比函数模板优先级更高)如果希望函数模板可以被特化、偏特化,应该使用类模板来封装。类模板可以被偏特化。总结:函数模板不能偏特化只能重载,函数模板的特化并不参与重载决议。这和直觉有点不同。注意:1. 对于模板函数。不能使用默认参数。默认参数仅仅对模板类有效。2. 在编写模板函数的过程中。函数体内所有使用到的类型都必须是已知的(当然对于template中的参数类型。在函数体内也属已经的类型)。就是说不能在函数体内使用新定义的类型。如果使用像迭代器这样的特化类型,需要使用typename 做限定。 阅读全文

[C++再学习系列] 模板函数的自定义点

2011-01-24 12:00 by zhenjing, 1014 阅读, 收藏, 编辑
摘要:在编写模板时,可以通过一些显示的自定义,对模板参数类型做一些必要的限制: 选择1: 模板直接依赖于类型具有给定名字的合适的成员函数, 则显式要求参数T提供该成员函数. 选择2: 模板依赖于”类型具有给定名字的合适的非成员函数”, 则显式的要求T具有给定名字/签名和语义的非成员函数. 选择3: 模板依赖于”类型已经特化(如果必要)另一个模板”, 则需要被特化的模板提供一个(通常是静态类成员)具有给定名字/签名和语义的函数. 阅读全文

[C++再学习系列] typename和依赖类型

2011-01-21 13:54 by zhenjing, 1024 阅读, 收藏, 编辑
摘要:template class Widget { ... }; class和typename均可用于声明模板的形式类型参数,但typename能更清楚地表示:T可以是任何类型;不必是一个类。为了避免潜在的模糊解析,编译器要求在依赖形式类型参数的类型名字之前使用typename。这样的类型被称为依赖类型。常见例子如容器迭代器。 阅读全文

[C++再学习系列] 深入new/delete:类域的operator new重载

2011-01-17 11:23 by zhenjing, 2856 阅读, 收藏, 编辑
摘要:为class 重载 operator new 时必须定义为类的静态函数(默认为static函数)。重载operator new更多的是为了提高程序效率,比如使用静态内存代替动态分配,启用小对象分配器等。但是要正确重载类域的operator new并不容易,有很多规则需要注意:1) 总是成对提供new/delete;2) 如重载operator new一定要同时提供标准形式的new。 阅读全文

[C++再学习系列] 深入new/delete:Operator new的全局重载

2011-01-13 12:01 by zhenjing, 1196 阅读, 收藏, 编辑
摘要:我们经常看到这么一句话:operator new可以重载,placement new不可重载。其实此处所说的不可重载应该是指全局的placement new不可重载,对于类域中的placement new是可以重载的。重载operator new规则:重载operator new 的参数个数是可以任意的, 只需要保证第一个参数为 size_t, 返回类型为 void * 即可, 而且其重载的参数类型也不必包含自定义类型. 更一般的说, operator new 的重载更像是一个函数的重载, 而不是一个操作符的重载。 阅读全文

[C++再学习系列] 深入new/delete:New的3种形态

2011-01-10 10:59 by zhenjing, 1969 阅读, 收藏, 编辑
摘要:短文介绍了New的3种形态: new operator 、 operator new 、 placement new。介绍了每一个种new背后的行为以及之间的区别,使用new的基本指南。同时给出placement new的基本使用准测。最后介绍如何使用new handler来定制new失败后的程序行为。 阅读全文

[C++再学习系列] 派生类函数的重实现规则(override-覆盖)

2010-12-02 12:00 by zhenjing, 1718 阅读, 收藏, 编辑
摘要:C++有重载(Overload),虚函数的重实现(override-覆盖),隐藏(Overwrite:覆盖hide)。这三者初学者容易混淆。其中重载最容易掌握,重实现也不容易出错,而已隐藏规则最为诡异,但其实隐藏完全就是C++的名字查找问题,明白名称查找规则后,一切就豁然了,不用再去记各种隐藏规则了。 阅读全文

[C++再学习系列] 虚函数的4条规则

2010-11-30 11:58 by zhenjing, 1331 阅读, 收藏, 编辑
摘要:虚函数的4条规则:1 尽量使用非虚拟接口模式 (NVI) 让接口函数成为非虚拟的。2 尽量让虚函数成为私用的。3 只有当派生类需要调用基类对某个虚函数的实现时,才把虚函数声明为保护的。4 基类的析构函数应该要么为共有虚函数 , 要么为保护虚函数。 阅读全文

[C++再学习系列] 隐式类型转换与转换操作符

2010-11-26 13:06 by zhenjing, 1304 阅读, 收藏, 编辑
摘要:C++标准允许隐式类型转换,即对特定的类,在特定条件下,某些参数或变量将隐形转换成类对象(创建临时对象)。如果这种转换代价很大(调用类的构造函数),隐式转换将影响性能。隐式转换的发生条件:函数调用中,当参数类型不匹配,如果隐式转换后能满足类型匹配条件,编译器将启用类型转换。控制隐式类型转换的两种途径:1) 减少函数调用的参数不匹配情况:提供签名(函数参数类型)与常见参数类型的精确匹配的重载函数。2) 限制编译器的启用隐式转换:使用explicit限制的构造函数和具名转换函数。 阅读全文

[C++再学习系列] 二元操作符重载

2010-11-24 12:48 by zhenjing, 1013 阅读, 收藏, 编辑
摘要:二元操作符重载的具体实现的标准方法如下:T& T::operator@=( const T& ) { // … implementation … return *this;}T operator@( const T& lhs, const T& rhs ) { T temp( lhs ) return temp @= rhs;} 阅读全文

[C++再学习系列] 前置++与后置++

2010-11-18 18:03 by zhenjing, 659 阅读, 收藏, 编辑
摘要:前置++与后置++听起来确实很简单,但如果动手写,估计自己是无法一次写出正确的版本的。 阅读全文

[C++再学习系列] 指针和引用

2010-11-12 17:57 by zhenjing, 1332 阅读, 收藏, 编辑
摘要:在指针和引用的小文中,主要讨论了引用和指针语法层面上的区别。本文将侧重如何更加合理地利用语言对引用所作限制。 阅读全文

[C++再学习系列] 引用和指针

2010-11-09 13:18 by zhenjing, 2786 阅读, 收藏, 编辑
摘要:引用和指针有如下三种区别: 1 引用必须在声明时初始化,而指针不用; 2 对于NULL不能引用,而指针可以指向NULL; 3 引用一旦声明,引用的对象不能改变(但对象的值可以改变);而指针可以随时改变指向的对象。 引用能做到的,指针也可以,但指针更危险; (1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。(2)不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是 NULL)。(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。本文将更深入地讨论这3个区别背后的意义。 阅读全文

[C++再学习系列] Using声明和指令的工作原理

2010-11-04 12:01 by zhenjing, 1830 阅读, 收藏, 编辑
摘要:对于C++编译器,那些名字可见是至关重要的,太多的名字可见将导致名字查找效率的降低。除了最常用的include可以导入可见名字之外,using关键字也可以导入名字到特定的编译单元中(单个cpp文件)。 本文将阐述using关键字的工作原理和使用准则。 阅读全文

[C++再学习系列] 可访问性问题

2010-11-03 13:15 by zhenjing, 318 阅读, 收藏, 编辑
摘要:C++通过Private,protected,public来控制成员的可访问性。本文将讨论如何改变类函数的可访问性,以及如何突破类函数的可访问性限制。 阅读全文

初学者:C++学习

2010-11-01 09:17 by zhenjing, 2147 阅读, 收藏, 编辑
摘要:这份笔记是分多次写成的。开始部分是当初学习C++的笔记。06年7月之前,做嵌入式开发的,比如单片机,DSP等,在7月14号最终确定彻底转向计算机方向,并分到一个项目组(学校),做流媒体服务器开发。之前开发汇编用得多,C懂点,C++根本不懂。开始的第一天拿到上千行的C++代码,彻底晕了,根本看不懂。于是接下来3天,看了 这本书,并写下了最初的这份笔记。后面的2周内,写出了3000多行的C++项目代码,虽然有bug,但这份经历对我影响很大。那些天每天工作都在12小时以上,眼睛都看花了。这份笔记对自己早已没多大价值,但这份经历却让我印象深刻。希望这些笔记对初学者能有所帮助! 阅读全文

对待拷贝构造函数和赋值函数的3种境界

2010-10-29 11:53 by zhenjing, 2291 阅读, 收藏, 编辑
摘要:对待拷贝构造函数和赋值函数有3种境界:不写;禁用;正确编写。具体细节详见正文,文中另外给出一些有关拷贝构造函数的语法细节,笔试有用吧,平时用不到。 阅读全文

C++析构函数不能失败的4个理由

2010-10-25 09:45 by zhenjing, 2372 阅读, 收藏, 编辑
摘要:C++的析构函数不能失败,即抛出异常(析构函数没有返回值)。但为什么不能失败呢?理由又是什么呢?假如面试被问到这个问题,您能说出几个理由呢? 阅读全文

[C++再学习系列] 类常量

2010-10-22 09:35 by zhenjing, 319 阅读, 收藏, 编辑
摘要:C++标准允许在类的定义中定义静态整数常量,但其他类型的类常量则需要单独的定义或将常量封装在函数中。此外,enum也常用于定于类常量。对于单独的类常量,static声明是必须的,这样才能保证所有的类常量公用一个地址空间。 阅读全文

[C++再学习系列] 跨编译单元的对象初始化

2010-10-21 22:06 by zhenjing, 518 阅读, 收藏, 编辑
摘要:C++对跨编译单元的名字空间级对象初始化顺序并未做定义。不仅如此,在调用对象自身的构造函数之前,编译器已经对名字空间级对象做了”零初始化”,即将内存值全部置零(不同于未初始化)。因此,绝对不能假定名字空间级对象的初始化顺序,更不能让名字空间级对象的初始化过程互相依赖。 阅读全文

揭秘:C++编译器的函数编译流程

2010-10-20 09:35 by zhenjing, 4410 阅读, 收藏, 编辑
摘要:介绍C++编译器在解析函数调用所涉及的三大步骤(流程):a)名字查找;b)重载决议;c)可访问性检查。了解编译器的工作流程有助于解释很多编译器的编译错误,并防止写出无法通过编译的代码。如能真正理解这些规则,很多C++编译错误就很容易解释了。 阅读全文

[C++再学习系列] 全局或静态变量(对象)的初始化

2010-10-15 13:11 by zhenjing, 3978 阅读, 收藏, 编辑
摘要:对于C语言的全局和静态变量,不管是否被初始化,其内存空间都是全局的;如果初始化,那么初始化发生在任何代码执行之前,属于编译期初始化。由于内置变量无须资源释放操作,仅需要回收内存空间,因此程序结束后全局内存空间被一起回收,不存在变量依赖问题,没有任何代码会再被执行! C++引入了对象,这给全局变量的管理带领新的麻烦。C++的对象必须有构造函数生成,并最终执行析构操作。由于构造和析构并非分配内存那么简单,可以相当复杂,因此何时执行全局或静态对象(C++)的构造和析构呢?这需要执行相关代码,无法在编译期完成,因此C++标准规定:全局或静态对象当且仅当对象首次用到时才进行构造,并通过atexit()来管理对象的生命期,在程序结束之后(如调用exit,main),按FILO顺序调用相应的析构操作! 阅读全文

[C++再学习系列] 具有链接的C++实体

2010-10-14 17:32 by zhenjing, 327 阅读, 收藏, 编辑
摘要:具有链接的实体,包括名字空间级的变量和函数,都是需要分配内存的。具有链接的实体如果在源文件(cpp)中出现多次,将意味着多次分配内存,每个内存空间定义一个特定的实体。这会导致:1) 空间膨胀;2) 出现多个变量,变量的状态不共享。 个人理解:何为具有链接的实体呢?通常而言,变量和函数的定义即是。 阅读全文

[C++再学习系列] 变量的声明、定义与extern关键字

2010-10-12 13:14 by zhenjing, 914 阅读, 收藏, 编辑
摘要:A definition of a variable allocates storage for the variable and may also specify an initial value for the variable. There must be one and only one definition of a variable in a program. A declaration makes known the type and name of the variable to the program. A definition is also a declaration: When we define a variable, we declare its name and type. We can declare a name without defining it by using the extern keyword. A declaration that is not also a definition consists of the object's 阅读全文

[C++再学习系列] 变量与声明时初始化

2010-10-12 11:24 by zhenjing, 1104 阅读, 收藏, 编辑
摘要: 未初始化的变量常常会导致一些奇怪的bug,有时还真不好调式。养成在初始化变量的习惯有利于减少编程错误,提高程序质量。 C++提供了构造和析构函数,其中构造函数就是为初始化而设计的;对于内置变量(char,int,long等)的初始化C++无能为力,其默认行为是未初始化,故其值依赖于变量类型(是否为static)和编译器。 本文中将讨论两类基本变量:标量和数组,标量指单一变量,数组本质上就是一整块内存空间(别忘了memset)。其他数据结构均基于这两类基本变量,一般由库提供,比如著名的C++ STL容器。 阅读全文