错误一:错记“<<”与“+”的优先级
因为“<<”和“>>”相当于乘除2^N,所以容易误认为它们的优先级高于加减运算,其实不然。当把它们跟加减法一起用的时候一定要注意。比如计算n*5:
result = n << 2 + n;
这样就错了,应该用括号:
result = (n << 2) + n;
错误二:“==”误写为“=”
这是一个比较低级却又难以发现的错误。说它低级是因为它属于再基本不过的语法问题;而它之所以难以发现是因为它不会产生编译错误,唯有在调试过程中跟踪执行才会发现。通常它导致的后果是某一个条件判断失效或者进一步导致死循环,比如:
if (rect.top = rect.bottom)
{
MessageBox(hwnd, "Invalid rectangle!", NULL, MB_OK | MB_ICONERROR);
}
因为条件判断误写成了赋值,上面的判断将永远为真,除非rect.bottom为零。
错误三:头文件重复包含
当你的工程越来越庞大时,头文件的管理也麻烦起来。经常遇到这样的情况:在编译一个源文件时,发现因为没有包含某个头文件而导致“符号未定义”之类的错误,于是你加入了这个头文件,可是这个头文件中又包含另外一个头文件,而那个头文件原先已经加在源文件中了,结果产生了“符号重定义”错误,这样你又不得不把这个重复包含的文件去掉……
为了避免出现“符号重定义”错误,可以采取条件编译技术。在创建头文件时,首先为这个头文件定义一个唯一的标识(假设是_SOME_SYMBOL_),然后在头文件的开头及结尾加上几行代码,像下面这样:
#ifndef _SOME_SYMBOL_
#define _SOME_SYMBOL_
....(头文件代码)
#endif
第一行语句判断是否定义了符号 _SOME_SYMBOL_,如果没有,说明本次编译尚未扫描过这个头文件,于是编译正常进行,并且定义符号_SOME_SYMBOL_,以标明文件已被扫描过一次;反之,如果文件已被包含过一次,_SOME_SYMBOL_就有了定义,于是条件编译语句使编译器跳过整个文件。
如果所有的头文件都这样处理,就可以大量减少出现“符号重定义”错误的机率。
错误四:指针未初始化
对于一个熟练的程序员来说,这决对是一个不该犯的错误。不过,有些初学者确实经常被这个问题弄胡涂。比如,曾见过有人这样写:
int *p;
*p = 0;
DOS下,这将有可能导致死机;WINDOWS下将导致一个非法操作。
切记,使用指针前一定要初始化,使它指向一个确实分配了的空间!!!
错误五:使用已释放了的指针
最常出现在释放链表时。初学者容易这样写:
while (p)
{
delete p;
p = p->next;
}
这样是很危险的。正确的方法是:
while (p)
{
q = p->next;
delete p;
p = q;
}
错误六:printf()/scanf()中类型不匹配
虽然WINDOWS下一般不用这两个函数了,但是与之类似的sprintf()/sscanf()和fprintf()/fscanf()还是经常使用的。
如果格式字串中说明的变量类型与后面的参数列表不一致,printf()将导致输出结果混乱,scanf()有可能导致程序执行结果不稳定,甚至导致非法操作。
初学者或许会以为类型不一致也无所谓,因为C语言可以自动进行类型转换。这种想法是错误的。类型转换是在编译时已知原类型和所需类型时由编译器产生代码来完成的,而格式字串对编译器来说只是一般的字串,编译器并不理解其中的含义,也就无法知道其中的类型信息;另一方面,从printf()/scanf()函数内部,虽然可以理解格式字串,但却无法知道后面变量表中的各变量的类型,对printf()/scanf()内部来说,变量表只呈现为一段连续的单元字节,唯一可知的是这段连续单元的起始地址
(待续……)
C语言基本功教程系列(1)
看了那么多文章,感觉到大家学习游戏程序设计的热情.经常看到很多人提出关于openGL directX,和computer graphics的问题. 但是我个人人为, 游戏程序设计,最最最重要的还是C C++语言的基本功. 如何编写高效率,整洁,和尽可能少的Bug的代码,是成为一个游戏程序设计员的关键. 所以我开拉这个小系列,来帮C或C++语言基础不牢靠的人补补基础知识,希望能够对大家有所帮助.
至于内容嘛,我想起来什么就写什么,不一定有什么逻辑关系.毕竟我工作也很忙,只有在每个milestone完了以后才有时间干点别的. 所以这里先道歉啦.
今天就讲讲最基本的循环.
int i;
for(i = 0; i < 100; i++)
{
// do something
}
也许很多人觉得这个代码是最简洁的了.其实不然, 还有更快速的写法.
i = 100;
do
{
// do something
}while(--j);
以下是visual studio .net 2003编译过的汇编代码.
================while loop================
j = 10;
00411A32 mov dword ptr [j],0Ah
do
{
}while(--j);
00411A39 mov eax,dword ptr [j]
00411A3C sub eax,1
00411A3F mov dword ptr [j],eax
00411A42 jne main+29h (411A39h)
================for loop================
for(i = 0; i < 10; i++)
00413656 mov dword ptr [i],0
0041365D jmp main+58h (413668h)
0041365F mov eax,dword ptr [i]
00413662 add eax,1
00413665 mov dword ptr [i],eax
00413668 cmp dword ptr [i],0Ah
0041366C jge main+60h (413670h)
{
}
0041366E jmp main+4Fh (41365Fh)
仔细分析就会发现while循环比for循环在每次的循环中都少一条汇编语句. 主要是因为while循环是从大到小的顺序循环,不需要和10进行比较就可以跳转.而且可以直接利用--j语句设置的符号标志进行条件判断.
同样是循环10次,但是少一条语句还很多关键的时候很有用哦.
以上是第一章,如果有不同意见,错误或者遗漏,请谅解哦.
这个,上边是debug version的代码。偷懒被人看出来,下面给出release版本经过编译器优化的代码,优化参数 /02 /0t:
============for loop=============
:00401029 xor eax, eax
:0040102b jmp 00401030
......
:00401030 .......
:00401035 inc eax
:00401036 cmp eax, 000000064
:00401039 jl 00401030
===========while loop============
:00401029 mov eax, 000000064
:00401030 ..........
.....
:00401035 dec eax;
:00401036 jne 00401030
C语言基本功教程系列(2) - if 语句
趁周末再写一章。今天就介绍下if语句
if语句很简单,相信大家都会,但是确有很多值得注意的。 首先来说一下code style的问题。
=========不好的风格===========
if( (x +4-y * 25) > 10 || y > 1023 || GetSomething())
{