关于C++中断言assert的转载及汇总

首先看MSDN上的解释:

Evaluates an expression and, when the result is false, prints a diagnostic message and aborts the program.

1
2
3
void assert( 
   int expression 
);

断言assert是一个宏,该宏在<assert>中,,当使用assert时候,给他个参数,即一个判读为真的表达式。预处理器产生测试该断言的代码,如果断言不为真,则发出一个错误信息告诉断言是什么以及它失败一会,程序会终止。

通常当我们使用assert时,都在强烈说明一个含义:在这里必然如此。即assert是指你绝对确信不可能会发生的事

摘录林锐博士高质量编程一书中相关内容。
~~~~~~~~~~~~~~~~~~~~~~~~
程序一般分为Debug版本和Release版本,Debug版本用于内部调试,Release版本发行给用户使用。
断言assert是仅在Debug版本起作用的宏,它用于检查“不应该”发生的情况。以下是一个内存复制程序,在运行过程中,如果assert的参数为假,那么程序就会中止(一般地还会出现提示对话,说明在什么地方引发了assert)。

1
2
3
4
5
6
7
8
9
void memcpy(void *pvTo, void *pvFrom, size_t size) 
{ 
	void *pbTo = (byte *) pvTo;
	void *pbFrom = (byte *) pvFrom; 
	assert( pvTo != NULL && pvFrom != NULL ); 
	while(size-- > 0 ) 
		*pbTo++ = *pbFrom++ ; 
	return (pvTo); 
}

assert不是一个仓促拼凑起来的宏,为了不在程序的Debug版本和Release版本引起差别,assert不应该产生任何副作用。所以assert不是函数,而是宏。程序员可以把assert看成一个在任何系统状态下都可以安全使用的无害测试手段。
以下是使用断言的几个原则:
1)使用断言捕捉不应该发生的非法情况。不要混淆非法情况与错误情况之间的区别,后者是必然存在的并且是一定要作出处理的。
2)使用断言对函数的参数进行确认。
3)在编写函数时,要进行反复的考查,并且自问:“我打算做哪些假定?”一旦确定了的假定,就要使用断言对假定进行检查。
4)一般教科书都鼓励程序员们进行防错性的程序设计,但要记住这种编程风格会隐瞒错误。当进行防错性编程时,如果“不可能发生”的事情的确发生了,则要使用断言进行报警。

网上还有一篇关于“断言”的大师级文章:

http://blog.csdn.net/zxcred/article/details/3239883

其他一些参考链接:

http://zhidao.baidu.com/question/119204684.html

http://topic.csdn.net/t/20040922/15/3398499.html

http://topic.csdn.net/t/20040718/20/3186411.html

http://bbs.chinaunix.net/thread-1185312-1-1.html

悲剧的第一次面试

今天参加了福昕软件北京分公司的实习面试,悲剧了。。。

我应聘的是C++软件工程师,公司有点不好找,我找了老半天,问了不下于20个人。。。才最终找到那个地方,上去后,做了一会,就来了一个面试官,让我一个人做了一份面试题,大部分题都还可以,就是有一个地方有点悲剧,因为最近C++搞的不多,导致纯虚函数那一块都忘光了,还有一题,是考察那个几种类型sizeof输出的大小,有int, double, float, void *,等等,我当时选了void *,后来他问,那么64位机下呢?石化了~~~

最悲剧的还是机试,我一只学的是Qt,结果他们说让我试试MFC,=。=  结果就是,一个多小时,望着VC6.0,望着MSDN,干瞪眼了一个多小时,最终无奈的离去。。。。

不过通过这次面试,还是发现了自己的很多不足,希望接下来要查漏补缺了,加油吧。

还有很长的路要走~~~~

函数指针简单讲解

因为基本没用过函数指针,所以对这个概念及用法比较模糊,最近温习C++在,再次看见这个概念,于是百度了下,看见网上有很多关于函数指针的文章,不过在纷纷转载的过程中,格式上的错位,让人看着难受,我自己也简单的总结下,方便以后查阅。

首先要清楚一个概念:

1.数组的数组名就这个数组的地址,也即数组第一个元素的地址(指针)。

2.函数的函数名就这个函数的入口地址(指针)。

3.结构体的结构名不是这个结构的地址,要取得结构体的地址,必须得用&(取地址运算符)。

其次,还得对函数指针,指针函数,数组指针,指针数组这四个容易混淆的概念区分清楚。(这个可以百度,网上资料太多了,一个小秘诀,这四个概念的主体都是后两字,比如数组指针,主体是指针,只不过这个指针指向一个数组,很容易理解吧?)。

上面说了:“函数名实际上也是一种指针,指向函数的入口地址”。

我们先来看一个函数指针最简单的例子,这个例子仅仅只为了展示函数指针这个概念,而无法体现其优点。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>    
using namespace std;
 
int fun(int a)      // ①
{
	cout << a << endl;
	return 0;
}
 
int (*pfun)(int);  // ②
 
int main()
{
	pfun = fun;   // ③
	(*pfun)(3);   // ④
	return 0;
}

运行结果:
pfun

首先看代码的①处,定义一个函数fun,输出参数的值;

再看②处,这里是函数指针的定义,因为括弧的优先级高于*,所以要把pfun用括弧包围,否则就变成指针函数了,返回一个指针int *.另外,函数指针的返回类型,参数个数,参数类型等都要和要匹配的参数一模一样!

再看③处,因为在②出是函数指针的定义,函数指针是一个指针,而函数名是函数的入口地址,所以把fun赋值给pfun,这样,pfun这个函数指针就指向fun这个函数了。

所以在④处,调用(*pfun)(3);就相当于调用fun(3)了。

但是看完这个例子,肯定脑海里对函数指针的作用毫无概念,不过起码函数指针的用法基本了解了,那么看下这个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include<iostream>
using namespace std;
 
void imax(int a, int b)
{
	cout << "Now call max(" << a << "," << b << "):" << endl;
	int t = a>b? a:b;
	cout << t << endl;
}
 
void imin(int a, int b)
{
	cout << "Now call min(" << a << "," << b << "):" << endl;
	int t = a<b? a:b;
	cout << t << endl;
}
 
// 定义一个函数指针
typedef void (*myFun)(int a, int b);
 
// 回调函数
void callback(myFun fun, int a, int b)
{
	fun(a, b);
}
 
int main()
{
	int a = 10;
	int b = 20;
 
	callback(imax, a, b);
 
	callback(imin, a, b);
 
	return 0;
}

运行结果:

callback

很直观的就可以看出函数指针的作用,有点类似函数模版。

一般都是把指向函数的指针作为另一个函数的形参,这样可以在运行时确定参数。

接下来简单说下typedef和函数指针:

我们一般定义函数指针是:

void (*pfun)(int, int);

不过,我们也可以用typedef:

typedef void (*pfun)(int, int);

请注意第一个是定义一个变量,而第二个是设置一个类型的别名,也即第二个的pfun实际上只是一个类型! 

更多的类容,我在网上找了几篇,不过有的格式比较混乱,将就下也无所谓:

1.http://dev.10086.cn/cmdn/wiki/index.php?doc-view-6757.html (推荐!)

2.http://zhangming3113.blog.163.com/blog/static/6217914820083911444353/

3.http://topic.csdn.net/t/20051016/20/4329907.html

4.http://zhaowei1119.blog.163.com/blog/static/7297435720095704327919/

TankyWoo 标签:

请不要忘记,还有“思考”这个东西

最近准备参加实习生招聘,于是开始关注起了各大公司的面试题,在看网易面试题的时候看到了这么一题:

为什么现在的计算机采用二进制?而不是八进制或十六进制?你认为以后的计算机会采用几进制?

我当时就在问自己,为什么?但是无果,我隐约记得很多书上都讲过,但是为了追求速度,追求更重要的知识,我把这部分内容给自动滤过了。

于是我又在想,是什么原因导致这样的呢?

我开始回忆我的学习过程,我发现,在大一大二开始接触编程时,我还是很喜欢思考的,但是为何后来就麻木了呢?

于是我又开始分析我的学习方法,没错,就是学习方法出问题了—我过于的追求速度,追求广泛,很多知识,我都是一扫而过,很多代码,我都是看一看就自以为懂了,曾经刚开始学时,我还经常把代码往电脑上敲,把代码抄在纸上,然而现在却是直接扫一下。

我想到了一个词—物极必反。虽然我看的很多,看的很快,但是收效却不大。

我突然就被惊醒了,是的,扪心自问一下,现在记在我脑海里的,还有多少知识呢?你了解的知识多吗?你看书仔细吗?

我相信很多人都和我一样,为了应付考试,应付以后的面试,工作,都在疯狂的看书,疯狂的吸纳知识,但是,你真的掌握了这些知识吗?

写到这里的时候,我又想起来我昨天在伯乐在线看到的一篇文章:学一门语言,要了解他的历史,哲学观,这也是一种思考:

比如文章中举例的:拿python来说,他的设计哲学是“用一种方法,最好是只有一种方法来做一件事”,而perl的设计哲学是“总有多种方法来做同一件事”。

其实,这是多么有趣的一件事,然后,就这样被大部分人给忽略了。想到这,我都替自己感觉到可惜。

幸好今天发现了这个问题,就像《让子弹飞》里面说的一样“步子要一步步的走,迈得大了,会扯着蛋”,确实,知识也要一步步的积累,没有什么快速掌握的方法,最好的办法就是一步一步的积累,要多思考,没有思考,就没有进步;没有思考,就没有升华。

我们应该时刻要记住,学,应该是一种享受的过程,重点不在于结果,而是过程,一种发散思维的过程。

希望自己能时刻记住这一点,能应付好接下来的实习生求职。

注:上面那个问题的答案,大家可以相互交流下,我在网上找到这篇讲的不错:

http://blog.csdn.net/hkx1n/article/details/4280036