C语言中的缺陷与陷阱
(博雅课期末作业:计算机网络安全与防护) 刚进大学,学的第一门计算机语言就是C语言,这是我第一次接触到计算机语言,对它一无所知。有些同学之前已经学过了一些类似的语言,例如VB、PASCAL等等。因为从来没有学过计算机语言,所以在学习C语言的过程中,遇到了很多困难,许多问题都不理解。因此虽然我已经学完了这本书,但是对书中的内容都不知甚解。
学过C语言的人都知道,指针是C语言中的一个重要概念,也是它的一个重要特色。正确而灵活地运用指针,可以有效地表示复杂的数据结构;能动态分配内存;方便地使用字符串;有效而方便地使用数组;在调用函数时能获得一个以上的结果;能直接处理内存单元地址等。掌握指针的应用,可以使程序简洁、紧凑、高效。但是任何事情都有两面性,C语言中的指针也是如此。举几个例子来说:
1.指针与数组
在新的一年里我们需要将日历(calendar)数组清空:
int (*monthp)[31];
for(monthp=calendar;monthp
{
}
在这个程序中用指针monthp以步进的方式遍历数组calendar。使用指针来操纵数组,常常需要跟C语言中最为“晦暗不明”的部分打交道,并常常遭遇到潜伏着的编译器bug。因此使用指针时,我们必须得小心翼翼,否则,程序很容易出错。
2.非数组的指针
有一段程序如下:
char *r,*malloc();
r=mollac(strlen(s)+strlen(t));
strcpy(r,s);
strcat(r,t); int *dayp; for(dayp=*monthp;dayp
这个例子有三个错误:一、malloc函数有可能无法提供请求的内存,这种情况下malloc函数会通过返回一个空指针来作为“内存分配失败”事件的信号。二、给r分配的内存在使用完成之后应该立即释放。三、最重要的是调用malloc函数是并未分配足够的内存。
3.数组边界问题
C语言并不检验数组边界,因此,数组的两端都有可能越界而使其他变量的数据甚至程序代码被破坏。因此对于C语言来说,数组的边界检验是程序员的职责。
C语言中一个拥有n个元素的数组中,却不存在下标为n的的元素,它的元素的下标范围是从0到n-1,使用数组时一定要注意到这一点。
4.表达式求值顺序
一个表达式:a
C中所有其它的运算符对操作数的求值顺序都是未定义的。事实上,赋值运算符不对求值顺序做出任何保证。
5.移位运算符
C语言中,在向右移位时如果被移位的对象是无符号数,那么空出的位将被0填充。如果被移位的对象是有符号数,那么C语言实现既可以用0填充空出的位,也可以由符号位的副本来填充空出的位。
移位计数也有一定的范围限制。如果被移位的对象长度是n位,那么移位计数必须大于或等于0,而严格小于n。因此,不可能做到在单次操作中将某个数值中的所有位都移出。
还要注意的是,即使C语言实现将符号位复制到空出的位中,有符号整数的向右移位运算也不等同于除以2的某次幂。
6.可移植性缺陷
C被很多人实现并运行在很多机器上。这也正是在一个地方写的C程序应该能够很容易地转移到另一个编程环境中去的原因。
然而,由于有很多的实现者,它们并不和其他人交流。此外,不同的系统有不同的需求,因此一台机器上的C实现和另一台上的多少会有些不同。
由于很多早期的C实现都关系到UNIX操作系统,因此这些函数的性质都是专于该系统的。当一些人开始在其他系统中实现C时,他们尝试使库的行为类似于UNIX系统中的行为。
但他们并不总是能够成功。更有甚者,很多人从UNIX系统的不同版本入手,一些库函数的本质不可避免地发生分歧。今天,一个C程序员如果想写出对于不同环境中的用户都有用的程序就必须知道很多这些细微的差别。
为了减少程序的错误,我们可以采取以下一些建议:
1.不要说服自己相信潜在的错误。有些错误极具伪装性和欺骗性。
2.直截了当的表明意图,这样做不仅有利于自己日后读程序,也方便其他人理解程序的用意和维护代码。
3.考察最简单的特例。这一原则适用于构思程序的工作方式,测试程序的工作情况和程序设计
4.使用不对称边界。
5.注意潜伏在暗处的Bug漏洞,避免使用那些“生僻”的语言特性。
6.防御性编程。对程序用户和编译器实现的假设不要过多!
最后总结一下这学期我上博雅课的所得:了解了很多关于安全方面的小软件,如USB dumper,USB cleanner,Flash Disk Alert,ereaser,屏幕录像专家等,学习了文档加密、解密、隐藏,听了有关网络攻击方面的内容,还在课后看了电影《黑客帝国》、《虎胆龙威》、《超人特工队》、《鹰眼》、《防火墙》。此外,我对word的功能也多了一些认识,比如可以对word文档加密、解密,选择性粘贴。这些对我以后在学习中都将会有很大的帮助。
参考文献:《C陷阱与缺陷》Andrew Koenig著
C语言中的缺陷与陷阱
(博雅课期末作业:计算机网络安全与防护) 刚进大学,学的第一门计算机语言就是C语言,这是我第一次接触到计算机语言,对它一无所知。有些同学之前已经学过了一些类似的语言,例如VB、PASCAL等等。因为从来没有学过计算机语言,所以在学习C语言的过程中,遇到了很多困难,许多问题都不理解。因此虽然我已经学完了这本书,但是对书中的内容都不知甚解。
学过C语言的人都知道,指针是C语言中的一个重要概念,也是它的一个重要特色。正确而灵活地运用指针,可以有效地表示复杂的数据结构;能动态分配内存;方便地使用字符串;有效而方便地使用数组;在调用函数时能获得一个以上的结果;能直接处理内存单元地址等。掌握指针的应用,可以使程序简洁、紧凑、高效。但是任何事情都有两面性,C语言中的指针也是如此。举几个例子来说:
1.指针与数组
在新的一年里我们需要将日历(calendar)数组清空:
int (*monthp)[31];
for(monthp=calendar;monthp
{
}
在这个程序中用指针monthp以步进的方式遍历数组calendar。使用指针来操纵数组,常常需要跟C语言中最为“晦暗不明”的部分打交道,并常常遭遇到潜伏着的编译器bug。因此使用指针时,我们必须得小心翼翼,否则,程序很容易出错。
2.非数组的指针
有一段程序如下:
char *r,*malloc();
r=mollac(strlen(s)+strlen(t));
strcpy(r,s);
strcat(r,t); int *dayp; for(dayp=*monthp;dayp
这个例子有三个错误:一、malloc函数有可能无法提供请求的内存,这种情况下malloc函数会通过返回一个空指针来作为“内存分配失败”事件的信号。二、给r分配的内存在使用完成之后应该立即释放。三、最重要的是调用malloc函数是并未分配足够的内存。
3.数组边界问题
C语言并不检验数组边界,因此,数组的两端都有可能越界而使其他变量的数据甚至程序代码被破坏。因此对于C语言来说,数组的边界检验是程序员的职责。
C语言中一个拥有n个元素的数组中,却不存在下标为n的的元素,它的元素的下标范围是从0到n-1,使用数组时一定要注意到这一点。
4.表达式求值顺序
一个表达式:a
C中所有其它的运算符对操作数的求值顺序都是未定义的。事实上,赋值运算符不对求值顺序做出任何保证。
5.移位运算符
C语言中,在向右移位时如果被移位的对象是无符号数,那么空出的位将被0填充。如果被移位的对象是有符号数,那么C语言实现既可以用0填充空出的位,也可以由符号位的副本来填充空出的位。
移位计数也有一定的范围限制。如果被移位的对象长度是n位,那么移位计数必须大于或等于0,而严格小于n。因此,不可能做到在单次操作中将某个数值中的所有位都移出。
还要注意的是,即使C语言实现将符号位复制到空出的位中,有符号整数的向右移位运算也不等同于除以2的某次幂。
6.可移植性缺陷
C被很多人实现并运行在很多机器上。这也正是在一个地方写的C程序应该能够很容易地转移到另一个编程环境中去的原因。
然而,由于有很多的实现者,它们并不和其他人交流。此外,不同的系统有不同的需求,因此一台机器上的C实现和另一台上的多少会有些不同。
由于很多早期的C实现都关系到UNIX操作系统,因此这些函数的性质都是专于该系统的。当一些人开始在其他系统中实现C时,他们尝试使库的行为类似于UNIX系统中的行为。
但他们并不总是能够成功。更有甚者,很多人从UNIX系统的不同版本入手,一些库函数的本质不可避免地发生分歧。今天,一个C程序员如果想写出对于不同环境中的用户都有用的程序就必须知道很多这些细微的差别。
为了减少程序的错误,我们可以采取以下一些建议:
1.不要说服自己相信潜在的错误。有些错误极具伪装性和欺骗性。
2.直截了当的表明意图,这样做不仅有利于自己日后读程序,也方便其他人理解程序的用意和维护代码。
3.考察最简单的特例。这一原则适用于构思程序的工作方式,测试程序的工作情况和程序设计
4.使用不对称边界。
5.注意潜伏在暗处的Bug漏洞,避免使用那些“生僻”的语言特性。
6.防御性编程。对程序用户和编译器实现的假设不要过多!
最后总结一下这学期我上博雅课的所得:了解了很多关于安全方面的小软件,如USB dumper,USB cleanner,Flash Disk Alert,ereaser,屏幕录像专家等,学习了文档加密、解密、隐藏,听了有关网络攻击方面的内容,还在课后看了电影《黑客帝国》、《虎胆龙威》、《超人特工队》、《鹰眼》、《防火墙》。此外,我对word的功能也多了一些认识,比如可以对word文档加密、解密,选择性粘贴。这些对我以后在学习中都将会有很大的帮助。
参考文献:《C陷阱与缺陷》Andrew Koenig著