- 博客(66)
- 资源 (1)
- 收藏
- 关注
原创 C++基础篇--运算符重载
运算符重载没有多高深复杂,但牵扯到的相关概念和语法变化不少,如果这块基石不牢固,读复杂C++代码时就只有雾里看花的份。运算符重载由来 C/C++中所有运算符(+-*/等)默认只用于基本数据类型(int floatdouble等),而对自定义的struct/class通常不适用,如: typedef struct TIMETAG { int hou
2015-09-01 15:04:19 2037
原创 C++基础篇--overload重载&override覆盖&overwrite隐藏
Overload、Override和Overwrite英文接近,比较容易混淆,再加上翻译五花八门,使用时张冠李戴,往往是今天清楚明天糊涂。这三个概念在前面章节已分别讨论,这里再集中比较,以作备忘:Overload(重载) 前面分析过C++函数重载是借助C++的name mangling机制,允许在同一作用域中出现多个同名不同参的函数,如:class Base{ in
2015-04-14 11:11:17 4144 1
原创 C++基础篇--成员函数同名隐藏(overwrite)
C++中成员函数间的各种关系比较复杂,之前介绍过重载和虚函数覆盖,今天再梳理另一种容易让人迷惑的机制--函数隐藏。先看两个例子:例1.成员函数public继承class Base{public: void fun1(int a){ cout << "Base::fun1(int a)" << endl; }};class Drv: public Bas
2015-04-13 15:18:15 5392
原创 C++基础篇--虚函数原理
虚函数算是C++最关键和核心的内容之一,是组件的基础。下面先列出一些相关名词,再围绕它们举例说明虚函数的本质实现原理。基础概念(英文部分来自C++编程思想) 1)绑定:Connectinga function call to a function body is called binding.(把函数调用和函数实现关联的过程) 2)早绑定:Whenbinding is pe
2015-04-03 17:14:51 1042
原创 硬件篇之字节序
很多人讨厌碰到字节序问题,跟它打交道就像走迷宫,每次都要牺牲不少脑细胞。即使这一次似乎搞清楚了,下次碰到还是要重新在大脑里构建和模拟。这里尽量做一个字节序问的完整备忘记录。主机字节序 多字节数据在内存中的字节排列顺序称为主机字节序,主机字节序基本由CPU硬件决定,某些CPU如X86、Z80等为little-endian;有些如moto6800、sparc等为big-endian;而有
2014-02-17 18:48:36 1660 2
原创 硬件篇之MMU
MMU即内存管理单元(Memory Manage Unit),是一个与软件密切相关的硬件部件,也是理解linux等操作系统内核机制的最大障碍之一。可以说,不懂MMU使很多人一直停滞在单片机与无OS的时代。博主之前对MMU也一直是雾里看花,似懂非懂。最近终于自认为云开雾散后,回头总结,感觉有几个概念是阻碍人们理解MMU的元凶。1)虚拟地址/物理地址 如果处理器没有MMU,CPU内部执行
2014-02-13 17:35:42 23388 13
原创 内存篇之栈溢出
“溢出”这个词很生动,水满则溢,前面说过栈就象一个容器,容器装满了,还要往里装东西,当然就会溢出了。 有两种不同情景都被称为栈溢出,一种是栈中的数据被越界覆盖,wiki中称这种情况为stack buffer overflow。一种常用的黑客攻击手段--栈溢出攻击,就是通过栈越界访问,用事先设计好的数据覆盖正常栈里的内容。比如把保存函数返回地址的栈内存用某段黑客代码的地址覆盖,函数结束时不
2013-12-24 17:36:53 15586 1
原创 内存篇之堆泄漏
“堆泄漏”即常说的内存泄漏,是嵌入式软件里的常见问题,会导致软件运行一段时间后内存耗尽。什么是”堆泄漏”? 内存分配和释放的操作是程序员根据需要动态随机发起,程序本身(或编译工具)无法自动判断某块已分配的内存什么时候不再被使用,必须由程序员自己手动调用free释放,以便为其他程序腾出空间。而一旦程序员忘记释放某块内存,它就不能回到可用内存,系统总的可分配内存就随之减少,这就是内存泄漏
2013-12-24 15:21:10 1748
原创 C潜规则篇之如何实现平台无关
或许大家都有这样类似经历:要在某平台上开发一个模块,很幸运找到了功能类似的参考代码,拿来修改却发现它是基于其它平台,底层接口完全不同,且全都嵌在代码里,要一个个改。面对一堆编译错误,用着麻烦,丢了可惜,真成了“鸡肋”。 C代码复用不象JAVA那么简单,一般都要经过移植才能在不同平台运行。但如果事先把平台相关部分集中在一起,形成平台隔离层,C程序也能做到代码基本平台无关。判定C代码级平台无
2013-12-13 16:06:53 2572
原创 指针篇之十三 函数指针精彩回调
回调函数定义 回调是通过函数参数传递到其它代码内的某一段可执行代码。或者说,凡是自己定义又主动传给其他模块调用的,都是回调。回调允许底层模块调用高层定义的子程序。 理解回调首先要明白什么是层次/模块,软件模块是广义概念,可以包括功能库(也称SDK)、C++对象、组件以及操作系统等,但所有这些最终基本都可以归结为函数实体库。因此下文中上层模块就是指库的调用方(caller
2013-12-13 13:03:47 1630
原创 关于嵌入式软件开发的一些思考
今天是第一次开始写技术博客, a dear dairy moment. 首先感谢这个论坛上那些已经进入计算机软件开发自由王国的前辈高手们,正是他们在网络上不求回报地留下一篇篇精辟文章,如一盏盏指路明灯,真正为后来者照亮前进的方向;同时也想鼓励那些仍然身处迷雾苦苦挣扎的摸索者,只要坚定信心不动摇,终有一天能够登堂入室,苦尽甘来,从此终身享受嵌入式软件开发这个超级好玩的游戏。不必担心,不要沮丧,虽然编
2013-12-07 23:03:04 3660 2
原创 C潜规则之保持语法简单
有些C语言语法比较生僻,且有其他常规方式替代,建议尽量避开这些装x的写法,少折腾自己,也少折磨别人。下面是个人主观感觉,仅供参考。原则是简单比复杂好。数组作函数参数 数组作为函数的参数传递时,会退化成一个地址,也就是说你写的是数组array[],编译器把它作为地址&array处理,既然如此不如直接写&array清楚而明确。结构体直接赋值 struct TEST{
2015-08-26 15:51:32 1252
原创 C++基础篇--作用域和自定义命名空间
引子 为引出本文主题,先举个例子,以便后文对照理解:某学校一年招了3个叫李明的学生,为便于区分:1)按年龄排序分别称大、中、小李明;2)把他们分到不同班,这样各班内部就没有同名的李明,而学校范围内可用1班/2班李明区分;3)大李明加入绘画协会,中李明加入书法协会,小李明加入绘画和外语协会,于是绘画协会里还要用大小或班级区分两个李明。基本几点:1.谈到重名,需要指定具体集合范围。全校
2015-03-23 17:19:57 6697
原创 C++基础篇—函数重载与Extern C
问题引出 之前提到C存在命名冲突问题,新的C++专门为此引入了namespace机制加以改进(后文介绍),此外还有另一种机制: int add(int i, int j) { return i+i; } float add(float a, float b, floatc) { return a+b+c; } void main()
2015-02-27 18:23:00 3137
原创 C++基础篇--this指针
1.C++篇—struct到class进化的第一步this指针很多程序员C语言基础不好,结果用了好多年C++,还是知其然而不知所以然,往往经不起别人一问”xx机制怎么实现的”?比如this指针就是C++的基础机制之一。this的来由设想我们是十几年前C++的设计者,从C的struct怎么进化到C++的class?struct里可以用函数指针作成员变量,并
2014-05-12 12:38:11 1080
原创 内存篇之程序内存消耗评价指标
嵌入式软件除CPU占用率或者说运行速度外,内存方面还有三大量化评价标准,即ROM size, Peak memory occupation和 max stack depth,虽然不属于什么官方标准,但这三点的确综合反映了程序内存占用方面的整体指标。 rom size既不是指exe文件大小,也不是lib文件大小,而是目标文件中有效二进制段大小。exe和lib文件中都有一些辅助段,如文件头/
2014-03-07 10:38:38 2986
转载 C语言文本方式和二进制方式打开文件区别
转自:http://blog.sina.com.cn/s/blog_50b7dd7101012979.html,我们都知道,文本文件和二进制文件在计算机上面都是以0,1存储的,那么两者怎么还存在差别呢?我觉得,对于编程人员,文本文件和二进制文件就是一个声明,指明了你应该以什么方式(文本方式/二进制)打开这个文件,用什么函数读写这个文件(读写函数),怎么判断读到这个文件结尾。具体的说:
2014-03-07 10:18:11 2399
原创 补遗篇之文件I/O
文件I/O库是ANSI C标准的一部分,换句话,任何标准C语言开发环境中都可以用fopen/fread/fwrite/fclose接口访问文件。这里强调与文件I/O相关的几个易混淆的问题。fopen/open的区别和联系 unix/linux下文件IO有两套接口,即fopen/open系列,它们区别又联系: a. fopen是标准C库接口,所有C开发环境都要支持它;op
2014-03-07 10:11:30 1468
原创 补遗篇之函数
函数怎么来的 函数最本质是跳转和压栈。 跳转早在汇编时代就广泛应用:做一个汇编子模块,需要时jmp到其起始地址,执行完jmp回之前的地址(想起学微机原理时一堆人围着单板机输入子模块指令,像发报一样)。 后来发现光有跳转也不够,赤裸裸去,再赤裸裸回,带不走一片云彩。于是想到可以划出一段内存空间,跳转到子模块时传递一些参数信息过去,顺带也可以把跳转前的地址也存进去,jmp
2014-02-28 20:50:18 942
原创 硬件篇之总线
博主除了画过几次PCB板子就没搞过硬件,但实践中感觉到,软件从根源上依附于硬件而存在,随硬件的不断演化而发展变化,掌握软件背后的一些硬件基础和发展脉络,编写软件时才能自信而不盲目,主动而不是机械地紧跟软硬件的变化。 比如总线,看起来它和一般程序员关系不大。但它却串联起很多问题:为什么片上RAM和外部RAM访问速度有差异;为什么CPU访问外部RAM速度慢;为什么访问IO设备更慢;为什么CP
2014-02-19 15:41:02 2552 1
原创 C优化篇之减少运算量
程序优化的另一个出发点是减少运行过程中的运算量,有两个大的思路: 1)把部分计算量转移到离线,或者说把一部分工作挪到程序之外,人为处理,以减轻程序本身压力。比如查表、浮点转定点以及其他数学算法的优化等。 2)分析和剔除代码中的多余水分,由于编译器能把一些简单的无效语句剔除,所以程序员可以做文章的地方一般就是循环体。查表 有些算法输入有限离散整数,输出固定的数据集合,
2014-02-16 22:47:31 3502 2
原创 C优化篇之优化内存访问
目前CPU运行速度远超过内存访问速度,且从趋势看这种速度差距还会越拉越大,提高内存访问效率将是软件优化重要而长期的课题。内存访问优化的一般性措施可大体分两方面:1)减少内存访问;2)调整代码使程序集中顺序地访问内存。一、减少内存访问的措施包括:a.充分利用寄存器 充分利用寄存器缓存数据,是减少内存访问的思路之一。C程序编译后哪些元素由寄存器存储,哪些又会放进内存,取决于CPU以及
2014-02-01 21:55:21 6590
原创 关于C语言优化
前几天看网上新闻,有人建议把编程纳入高考,且不论是否靠谱,却至少说明一件事:会写点程序不再有什么可炫耀的,将来更有可能成为全民普及技能。其实即使现在,很多人写程序的兴奋感还没消退,就悲哀地发现自己程序写得蹩脚,反倒成为了周围人的笑料。 一群搞技术的人在一起,能脱颖而出的往往不是代码写得快的那个,而是对技术理解深且能在关键时刻分析解决问题的。掌握一些C语言优化知识,能增强这方面的气场和
2014-01-04 14:21:26 1046 1
原创 补遗篇之volatile
C中volatile关键字在程序操作变量时,强制读写变量所在内存,以阻止编译器对某些特殊变量的错误优化。反过来,只有靠程序员用volatile过滤一些特殊情况后,编译器才能大胆优化。volatile作用可总结为:阻止三种情形下的两种编译器优化。两种编译器优化 a. 数据流分析优化:编译器分析程序中变量在哪里赋值、哪里使用、哪里失效,根据分析结果消除多余的变量读取和赋值步骤,如:
2013-12-29 14:36:03 826
原创 补遗篇之内联与内嵌
从没想过有人会把这两个毫不相关的概念混为一谈,可招聘时还真就碰到问内嵌答内联,问内联答内嵌的情况。上网一查,原来内嵌汇编也常被叫内联汇编,中文表述IT名词时真就这么乏力么?蹩脚的撞名一个接一个。 内联函数即inline函数,其作用是“建议”编译器展开函数,不是一定展开,除非设置强制内联(如gcc的__attribute__((always_inline)))。展开即把函数代码插入被调用位
2013-12-27 12:24:31 1373
原创 补遗篇之C字符串
C并没有字符串类型,C字符串是一个以null('\0')结尾的字符数组,用null标识字符串结束。如{'a','b','c','d','\0'},只有包含这个'\0’才算C字符串。注意null也好,'\0'也罢,都只是0的不同表达,如: char a[] = “ABCDEF”; printf(“a=%s\n”,a); a[2]=0; printf(“a=%s
2013-12-27 10:42:31 1254
原创 补遗篇之sizeof
sizeof是C的单目运算符,它给出操作数存储所需的字节数,其操作数可以是表达式或类型名。sizeof()是运算符,不是函数,没有函数调用开销。其结果是在编译阶段由编译器自动给出,相当于常数,不象函数那样在运行时才得到返回值。 sizeof常用来屏蔽同一类型变量在不同平台上占用不同空间的问题,能提高C程序的可移植性。不懂得利用sizeof就出现:int *p = malloc(800
2013-12-26 22:41:44 965
原创 补遗篇之单行道标志const
面试时,问及const的含义,很多人会答:"const表示常量",这可不是考英文翻译,const应该更近似"只读"而不是常量。const语法 对非指针变量,const无论放在类型前或后,都表示变量属性为只读,运行过程中不能也不会赋值修改。如const int a;和int const a;这两种方式const作用相同,都表示a是一个常整型数。 而const修饰指针时则有所不
2013-12-26 20:59:34 923
原创 内存篇之越界访问
由于C语言指针高度灵活和自由,导致内存操作中陷阱很多,比如之前的堆泄漏,栈溢出,野指针等,此外还有一种常见的“内存访问越界”错误。广义讲,栈溢出也属于内存越界,只是对同一问题站在不同角度的说法。下面看几个内存越界的例子: void test1() { char string[10]; char* str1 = "0123456789";
2013-12-25 19:03:56 3789
原创 内存篇之野指针
前面两文中内存错误释放以及错误访问指向栈的指针,从另外角度,其中一部分错误还可以归结为访问了野指针。野指针又称悬挂指针,代表那些指向不可用内存区域的指针。操作野指针,程序会发生难以预料的错误。形成野指针主要有以下原因:1)指针没有初始化。指针变量创建时不会自动指向null,其缺省值是随机的,比如: int *p; *p = 0; 这种代码可能导致死机或者非法操
2013-12-25 18:58:11 1234
原创 内存篇之堆的错误释放
在我开始写程序时因为担心某些分支下忘记释放内存导致泄漏,就想能不能保险点,多加几次释放,但很快发现堆内存不能重复释放,一些错误释放甚至会导致系统崩溃。这类错误可分几种情况:1)重复释放某指针指向的内存,多数由于调用了不同层的子函数重复释放同一内存,如: int* p = malloc(20); …… free (p); …… System_
2013-12-25 10:18:57 2593
原创 内存篇之指向栈的指针
下面程序运行有什么样的结果? char *GetString(void) { char array[6]; strcpy(array, “hello”); return array; } void main() { char *pstr = NULL; pstr = GetStr
2013-12-25 09:29:00 2929
原创 内存篇之静态与动态分配
经常听到诸如静态分配/动态分配以及静态库等类似表述,这些究竟是什么含义呢?老规矩,看看万能wiki上的定义:“The word static refers to things that happen at compile time and link time when the program is constructed--as opposed to load time or run ti
2013-12-24 13:13:45 1046
原创 内存篇之程序内存布局
程序内存布局是理解软件本质的基础要素。支持一个程序运行的所有内存大体可分为以下几部分,或者说程序运行需要系统为其提供如下几部分存储区域: 栈:由编译器自动分配释放,存放函数参数,局部变量等,特点为后进先出。 堆:程序员调用malloc/free进行内存动态分配和释放所操作的内存区域。 全局数据区(静态区):全局变量以及static变量存放的内存区,注意static变量
2013-12-24 12:50:25 996
原创 内存篇之堆与栈的绕口令
堆(heap)/栈(stack或call stack)是两块功能完全不同的系统内存区,堆内存是由malloc/free函数动态申请和回收,而栈则是编译器与启动代码或线程创建代码配合,约定用CPU某寄存器标识最新使用位置的一段内存(所以分系统栈与任务栈,见后文)。但不知是谁添乱,用“堆栈”这个词代表“栈”的含义,导致中文里“堆“、“栈”和“堆栈”混在一起,三者的关系就象绕口令,“堆为堆,栈是栈,堆栈
2013-12-23 21:54:52 1274
原创 补遗篇之命名空间污染
概念 C标准规定,除非用static限定,否则全局变量与函数都作用于全局(见补遗篇static),也就是说一个模块中定义的函数与全局变量可在所有其他模块中被调用。这导致C的符号命名没有层次,不同模块间名字相互冲突的概率很高。学术的表述就是:C命名空间易被污染。 比如,不同软件模块中定义了同名但不同实现的非static函数,由于它们都全局可见,编译器链接时无法正确区分和选择这些同
2013-12-17 14:24:31 3807 2
原创 C陷阱篇之常见手误
C的某些语法容易让人不小心触雷,比如从0开始的下标 很多高级语言中,定义n个元素的数组,下标范围是从1到n,但C特殊,n元素的C数组中没有下标为n的元素,只有从0到n-1的下标。所以使用C数组时不要犯这种错误:int i, a[10];for ( i = 1; i 时超出数组边界八进制or十进制常数 C编译器会把数字025当作八进制,等于十进制的21,因此在使用
2013-12-17 11:26:29 921
原创 C陷阱篇之复合表达式中的确定与不确定
操作数求值顺序不定 C只规定小部分运算符以已知、特定顺序对其操作数求值,其他运算符的求值顺序没有定义,有偶然性。如a ,C标准规定:先求a,如a成立,再求c并计算整个表达式的值。任何编译器都不会先算c再算a,即&&运算符的求值顺序在C标准中有明确规定,先左后右。但下到a粒度时,C编译器对a和b的分别求值就没有先后规定,各种可能性都有。 C里只规定了四个运算符(&& ||,和?
2013-12-16 15:45:56 1096
原创 C陷阱篇之语法正确语义错误的编译器局限
编译器功能只是语法检查,只要语法正确,那它就遵循一个原则:程序员总是对的。其实也只能这样,如果脑子里想着A,实现的却是B,而A/B语法上都成立,那编译器除了认为你正确,还能做什么呢?只能我们自己注意区分A/B相似且语法都成立的下列情况。代码布局与缩进的误导 计算机从不受代码语法和布局影响,而人却易受眼睛影响做出倾向性判断,这些判断有时是错误的。如: for (i=0; i
2013-12-16 13:25:52 1910 1
原创 C陷阱篇之运算符优先级
C语言运算符有不同优先级,标准里对这些优先级的规定基本符合人们的正常认知习惯,但其中还有个别容易混淆。其实也不需要死记硬背所有优先级,只要注意几个例外就可以了:“+-”与”>>”运算符 因为和>>某些情况下相当于乘/除2n,很多人总认为它们的优先级也等于乘除而高于加减,但实际上移位运算优先级比加减低。这跟惯常思维不一致,所以当移位加减一起用时一定要注意。比如有人把n*5写成“res=
2013-12-15 21:45:22 928
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人