2013年10月27日
摘要: 今天在看《深入理解C++11》的时候,看到一段有意思的代码:int (*(*pf())())() { return nullptr; }我立刻就懵了——从来没有见过这样的函数声明。那么它究竟是一个怎样的函数呢?我努力回忆起《C专家编程》一书的内容,把其中解读变量声明的方法应用于该函数上,最终读懂了该函数。下面是大致的解读过程。首先,要确定声明中出现的操作符的优先级。显然,函数调用操作符()的优先级是高于指针解引用操作符*的。另外,小括号总是具有最高优先级。其次,要确定在声明中标识符与某个操作符结合起来的时候有什么意义。例如:a() a是一个函数*a a是一个指针由于函数声明的特殊性,当指... 阅读全文
posted @ 2013-10-27 22:08 Zplutor 阅读(7353) 评论(2) 推荐(1) 编辑
  2012年12月4日
摘要: 字符串与数值互相转换是非常常用的功能,大家都对它习以为常了。我想除了程序库的编写者之外,没有人会像我这样为了这个问题纠结一两天。C提供了一套函数用于字符串与数值互转换,包括itoa,atoi,strtol等。为了方便叙述,我将这套函数抽象成下面两个伪C函数:string C_IntToStr(int value, int radix);int C_StrToInt(string str, int radix);根据函数名称就可以知道它们的用途。注意本文只讨论整型值,浮点数不在该范围内。对于十进制的转换来说,这两个函数的行为很正常;对于非负数的非十进制转换来说,也很正常。这都没什么好说的。可是对 阅读全文
posted @ 2012-12-04 14:48 Zplutor 阅读(1576) 评论(0) 推荐(0) 编辑
  2012年3月20日
摘要: 有一个网络应用程序,需要创建子进程,同时要将一个内核对象的句柄传递给子进程使用。句柄默认是不可继承的,为了达到这个目的,要在创建内核对象的时候指定其句柄是可继承的,然后在调用CreateProcess的时候将bInheritHandles参数设置为TRUE,像下面那样(以创建Mutex为例): SECURITY_ATTRIBUTES sa = { 0 };sa.nLength = sizeof(s... 阅读全文
posted @ 2012-03-20 19:47 Zplutor 阅读(2919) 评论(2) 推荐(1) 编辑
  2012年2月23日
摘要: 最近在写一个网络程序,需要将字符串一行一行地写入套接字,再一行一行地从套接字读取出来。由于没有现成的函数来以行的方式来操作套接字,只能自己编写这样的函数了。忽然想到C++ 标准的IO库可以非常方便地操作输入输出流,不知道能不能将其扩展,应用到套接字上呢?回答是肯定的,标准库本身就是一个可方便扩展的库,在《C++标准程序库》一书中详细地讲解了如何对其进行扩展。下面的内容就是根据这本书的指导写出的,主要是我自己对其中的一些理解,所以跟书上的很相似。首先来看一下标准库中有关IO的类体系结构:除了ios_base之外,其它类都定义为模板,这是因为C++中有两种字符类型:char和wchar_t。ios 阅读全文
posted @ 2012-02-23 22:16 Zplutor 阅读(2652) 评论(3) 推荐(2) 编辑
  2011年9月25日
摘要: 本文写于我对C++尚不是很了解的时期,所以文中存在很多漏洞。为了避免浪费你的时间,请绕道!所有的C、C++教科书都警告我们:不要通过函数来返回struct或 class对象,否则会造成内存复制以及复制构造函数的调用,降低性能。相信这句话已经成为了一个常识,大家都能牢记于心。然而,有时候我们不得不违反这个警告,例如,通过函数获取一个std::string对象(以个人的经验而言,这种情况是很常见的,我经常要通过函数创建一个新的对象)。不知道从什么时候起,当我面对这种情况的时候会通过引用来获取这个对象,像这样:std::string GetString();std::string& str 阅读全文
posted @ 2011-09-25 16:28 Zplutor 阅读(20683) 评论(11) 推荐(2) 编辑
  2011年9月17日
摘要: 我对.Net的委托模型印象很深刻,使用委托,可以快速实现观察者模式,免去写很多繁杂重复的代码。遗憾的是,C++并没有提供这样的模型,为了达到相似的目的,需要继承一个类并重写virtual方法,这种做法需要写很多代码,效率比较低下(使用过MFC的应该都能体会到)。然而,在强大的C++面前,没有什么是不可能的,已经有很多人针对这个问题进行过研究,并且实现了各种委托模型,其中最著名的就是FastDelegate,这个模型在《Member Function Pointers and the Fastest Possible C++ Delegates》中提出(原文地址:http://www.codep 阅读全文
posted @ 2011-09-17 18:55 Zplutor 阅读(16403) 评论(22) 推荐(5) 编辑
  2011年8月6日
摘要: 看到有一位同学在头文件中这么写:static const wchar_t* g_str1 = …static const wchar_t* g_str2 = …这种定义变量的方式我从来没有见过,而且它还能顺利通过编译,于是我很想知道编译器是如何处理这种变量定义的。定义全局变量时使用static,意味着该变量的作用域只限于定义它的源文件中,其它源文件不能访问。既然这种定义方式出现在头文件中,那么可以很自然地推测:包含了该头文件的所有源文件中都定义了这些变量,即该头文件被包含了多少次,这些变量就定义了多少次。假如将上面两行代码的static去掉,编译的时候就会出现变量重定义的错误,这进一步证实了上 阅读全文
posted @ 2011-08-06 13:43 Zplutor 阅读(28387) 评论(5) 推荐(7) 编辑
  2011年7月5日
摘要: 在进行网络编程时,可能需要直接操作原始的IP数据报,例如编写网络嗅探器。此时要定义一个表示IP数据报首部的结构体来获取首部中的各个信息,问题也随之而来:平时我们使用的数据都是BYTE、WORD或者DWORD,但IP数据报首部的有些字段并不按照字节、字或双字对齐,字段的长度也不是一字节、两字节或四字节,这种不一致的现象使得结构体的定义很有难度。我见过几种IP数据报首部结构体的定义,虽然方法各异,但都是大量使用union,将几个字段塞进一个BYTE或WORD中,在代码中还要通过移位、按位与等操作获取实际的字段。其实,只要理解数据在内存中是如何摆放的,以及利用好结构体定义的特性,可以最大限度地使结构 阅读全文
posted @ 2011-07-05 21:07 Zplutor 阅读(4001) 评论(0) 推荐(0) 编辑
  2011年4月23日
摘要: 本文讲解如何在调试器中显示函数调用栈,如下图所示:原理首先我们来看一下显示调用栈所依据的原理。每个线程都有一个栈结构,用来记录函数的调用过程,这个栈是由高地址向低地址增长的,即栈底的地址比栈顶的地址大。ESP寄存器的值是栈顶的地址,通过增加或减小ESP的值可以缩减或扩大栈的大小。上一篇文章已经简略地介绍过在调用函数时线程栈上会发生什么事情,现在我们再来详细地看看这个过程:①在栈上压入参数。②执行CALL指令,在栈上压入函数的返回地址。③压入EBP寄存器的值。④将ESP寄存器的值赋给EBP寄存器。⑤减小ESP寄存器的值,为局部变量分配空间。⑥执行函数代码。⑦将EBP寄存器的值赋给ESP寄存器,等 阅读全文
posted @ 2011-04-23 11:19 Zplutor 阅读(9841) 评论(13) 推荐(7) 编辑
  2011年4月22日
摘要: 上回介绍了微软的符号模型,有了这个基础知识,这回我们向MiniDebugger中添加两个新功能,分别是显示变量列表和以指定类型显示内存内容。显示变量列表用于列出当前函数内的局部变量或者全局变量;以指定类型显示内存内容用于读取指定地址处的内存内容,然后将这些二进制数据按照类型的格式解析成可读的内容并显示出来。如下面的截图所示:使用lv命令显示局部变量时,每一列从左到右分别是:类型,名称,长度,地址,值。只有基本类型、枚举类型以及指针类型的变量才会显示它的值,对于数组类型和UDT类型的变量则不显示它的值。获取这些变量的值需要使用f命令,该命令遵守同样的显示规则。下面介绍这两个命令的实现方法。枚举全 阅读全文
posted @ 2011-04-22 18:44 Zplutor 阅读(7083) 评论(5) 推荐(3) 编辑