15.1 编译程序中的C++扩充功能可以用在C程序中吗?
不可以,它们只能用在真正的C++程序中。
C++中的一些突出性能已被ANSI/ISO C标准委员会所接受,它们不再是“C++扩充功能”,而已经成为C的一部分。例如,函数原型和const要害字就被补充到C中,因为它们确实非常有用。
有一些C++性能,例如内联(inline)函数和用const代替#define的方法,有时被称为“高级C”性能。有些C和C++共用的编译程序提供了一些这样的性能,你可以使用它们吗?
有些程序员持这样一种看法:假如要写C代码,就只写C代码,并且使它能被所有的C编译程序接受。假如想使用C++性能,那么就转到C++上。你可以循序渐进,每次用一点新的技巧;也可以一步到位,用大量的内联函数,异常处理和转换运算符编写模块化的抽象基类。当你跨过这一步之后,你的程序就是现在的C++程序了,并且你不要指望C编译程序还会接受它。
笔者的看法是:你的工作是从一个新的C标准开始的,这个标准中包含一些C++性能和一些崭新的性能。在以后的几年中,一些编译程序的开发商会去实现这些新的性能的一部分,但这并不能保证所有的编译程序都会去实现这些性能,也不能保证下一个C标准会纳入这些性能。你应该保持对事态发展的关注,当一项新的性能看上去已经真正流行起来,并且不仅仅出现在你现在所使用的编译程序中,而是出现在所有你可能用到的编译程序中时,你就可以考虑使用它了。例如,假如过去有人非要等到1989年才开始使用函数原型,那么这其实就不是一种明智之举;另一方面,在保证可移植性的前提下,过去也没有一个开始使用noalias要害字的最佳时机。
请参见:
15.2 C++和C有什么区别?
15.2 C++和C有什么区别?
这个问题要从C程序员和C++程序员两个角度去分析。
对C程序员来说,C++是一种古怪的难以把握的语言。大多数C++库无法通过C编译程序连接到c程序中(在连接时编译程序必须创建模型或“虚拟表”,而C编译程序不提供这种支持)。即使用c++编译程序来连接程序,c程序仍然无法调用许多C++函数。除非非常小心地编写c++程序,否则C++程序总会比类似的c程序慢一些,并且大一些。C++编译程序中的错误也比C编译程序中的多。C++程序更难于从一种编译程序移植到另一种编译程序上。最后一点,C++是一种庞大的
难以学会的语言,它的定义手册(1990)超过400页,而且每年还要加入大量的内容。另一方面,c语言是一种既漂亮又简炼的语言,并且这几年来没有什么改动(当然不可能永远不会有改动,见14.1)。C编译程序工作良好,并且越来越好。好的c程序可以很方便地在好的C编译程序之间移植。虽然在C中做面向对象的设计并不轻易,但也不是非常困难。假如需要的话,你(几乎)总是可以用c++编译程序来生成C程序。
对于C++程序员来说,c是一个好的开端。在C++中你不会重犯在C中犯过的许多错误,因为编译程序不会给你这个机会。C的有些技巧,假如使用稍有不当,就会带来很大的危险。
另一方面,c++是一种优秀的语言。只需应用少数原则,稍作一点预先的设计工作,就能写出安全、高效并且非常轻易理解和维护的C++程序。用有些方法写C++程序,能使C++程序比类似的C程序更快并且更小。面向对象的设计在C++中非常轻易,但你不一定要按这种方式工作。编译程序日臻完善,标准也逐渐确立起来。假如需要的话,你随时可以返回到C中。
那么,c和C++之间有什么具体的区别呢?C的有些成分在c++中是不答应使用的,例如老式的函数定义。大致来说,C++只是一种增加了一些新性能的C:
·新的注释规则(见15.3);
·带有真正的true和false值的布尔类型,与现有的c或c++程序兼容(你可以把贴在显示器上的写着“O=false,1=true”的纸条扔掉了。它仍然有效,但已不是必须的了)。
·内联函数比#define宏定义更加安全,功能也更强,而速度是一样的。
·假如需要的话,可以确保变量的初始化,不再有用的变量会被自动清除。
·类型检查和内存治理的功能更好,更安全,更强大。
·封装(encapsulation)——使新的类型可以和它们的所有操作一起被定义。c++中有一种complex类型,其操作和语法规则与float和double相同,但它不是编译程序所固有的,而是在C++中实现的,并且所使用的是每一个C++程序员都能使用的那些性能。
·访问权控制(access contr01)——使得只能通过一个新类型所答应的操作来使用该类型。
·继续和模板(inheritance and templates)——两种编写程序的辅助方法,提供了函数调用之外的代码复用方式。
·异常处理(exceptions)——使一个函数可以向它的调用者之外的函数报告问题。
·一种新的I/O处理方法——比printf()更安全并且功能更强,能把格式和要写入的文件的类型分离开。
·一个数据类型丰富的库——你永远不需要自己编写链表或二叉树了(这一点是千真万确的!)。
那么,c和c++哪一个更好呢?这取决于多种因素,例如你做什么工作,你和谁一起工作,你有多少时间能用于学习,你需要并且能够使用的工具是什么,等等。有些C++程序员永远不会再返回到C,也有一些c程序员是从C++返回到C的,并且乐于使用C。有些程序员虽然也在使用一些C++性能和一种C++编译程序,但他们并没有真正理解C++,因此他
们被称为“用c++编写C程序”的人。还有一些人用C(和C++)编写FORTRAN程序,他们永远不会理解C或C++。
优秀的语言并不能保证产生优秀的程序。只有优秀的程序员才会理解他所用的语言,并且不管他用的是什么样的语言,他都能用它编写出优秀的程序。
请参见:
15.1 编译程序中的C++扩充功能可以用在C程序中吗?
15.3 在c程序中可以用“∥”作注释吗?
不行。有些C编译程序可能支持使用“∥”,但这并不说明可以在C程序中使用“∥”。
在c中,注释以“/*”开始,以“*/”结束。c的这种注释风格在c++中仍然有效,但c++中还有另一种注释规则,即从“∥”到行尾之间的内容(包括“∥”)都被认为是注释。例如,在C中你可以这样写:
i+=1;/*add one to i*/
这种写法在C++中也是有效的,而且下面这行语句也同样有效:
i+=1;∥add one to i
C++的这种新的注释方法有这样一种好处,即你不用记着去结束一行注释,而在注释c程序时你可能会忘记去结束一段注释:
i+=1;/*add one to i
printf("Don't worry,nothing will be"); /*oops*/
printf("lost\n”);
在这个例子中只有一段注释,它从第一行开始,到第二行的行尾结束。要打印"Don't worry"等内容的那个printf()函数被注释掉了。
为什么c++的这种性能比其它性能更轻易被c编译程序接受呢?因为有些编译程序的预处理程序是一个独立的程序,假如c和C++编译程序使用相同的预处理程序,C编译程序可能就会让这个预处理程序来处理这种新的C++注释。
C++的这种注释风格最终很可能会被c采用。假如有一天,你发现所有的C编译程序都支持“∥”注释符,那么你就可以大胆地在程序中使用它了。在此之前,你最好还是用“/*”和“*/”来注释C程序。
请参见:
第5章“编译预处理”开头部分的介绍
5.2 预处理程序有什么作用?
15.1 编译程序中的C++扩充功能可以用在C程序中吗?
15.4 char,short,int和long类型分别有多长?
其长度分别为一字节,至少两字节,至少两字节和至少4字节。除此之外,不要再依靠任何约定。
char类型的长度被定义为一个8位字节,这很简单。
short类型的长度至少为两字节。在有些计算机上,对于有些编译程序,short类型的长度可能为4字节,或者更长。
int类型是一个整数的“自然”大小,其长度至少为两字节,并且至少要和short类型一样长。在16位计算机上,int类型的长度可能为两字节;在32位计算机上,可能为4字节;当64位计算机流行起来后,int类型的长度可能会达到8字节。这里说的都是“可能”,例如,早期的Motorala 68000是一种16/32位的混合型计算机,依靠于不同的命令行选项,一个68000编译程序能产生两字节长或4字节长的int类型。
long类型至少和int类型一样长(因此,它也至少和short类型一样长)。long类型的长度至少为4字节。32位计算机上的编译程序可能会使short,int和long类型的长度都为4字节——也可能不会。
假如你需要一个4字节长的整型变量,你不要想当然地以为int或long类型能满足要求,而要用typedef把一种固有的类型(一种确实存在的类型)定义为你所需要的类型,并在它的前后加上相应的#ifdef指令:
#ifdef FOUR_BYTE_LONG
typedef long int4;
#endif
假如你需要把一个整型变量以字节流的方式写到文件中或网络上,然后再从不同的计算机上读出来,你可能就会用到这样的类型(假如你要这样做,请参见15.5)。
假如你需要一个两字节长的整型变
量,你可能会碰到一些麻烦!因为并不一定有这样的类型。但是,你总是可以把一个较小的值存放到一个由两个char类型组成的数组中,见15.5。
请参见:
10.6 16位和32位的数是怎样存储的?
15.5 高位优先(big—endian)与低位优先(1ittle—endian)的计算机有什么区别?
15.5高位优先(big—endian)与低位优先(little-endian)的计算机有什么区别?
高位优先与低位优先的区别仅仅在于一个字的哪一端是高位字节。换句话说,两者的区别在于你是喜欢从左向右数,还是喜欢从右向左数。但是,哪种方式都不见得比另一种方式更好。一个可移植的C程序必须能同时适用于这两种类型的计算机。
假设你的程序运行在short类型为两字节长的计算机上,并且把值258(十进制)存放到地址s3000H处的一个short类型中。因为short类型的长度为两字节,所以该值的一个字节存放在3000H处,另一个字节存放在3001H处。258(十进制)即0102H,所以该值的一个字节的内容为1,另一个字节的内容为2。那么,究竟内容为1和2的字节分别是哪一个呢?
其答案因机器的不同而不同。在高位优先的计算机上,高位字节就是低地址字节(“高位字节”指的是其值变化后使整个字的值变化最大的那个字节,例如,在值0102H中,01H就是高位字节,而02H是低位字节)。在高位优先的计算机上,字节中的内容如下所示:
地址 2FFEH 2FFFH 3000H 3001H 3002H 3003H
值 01H 02H
这种图示方式很直观——地址就象是尺子上的刻度值,低地址在左,高地址在右。
在低位优先的计算机上,字节中的内容如下所示:
地址 3003H 3002H 3001H 3000H 2FFFH 2FFEH
值 01H 02H
这种图示方式同样很直观——低位字节存放在低地址中。
不幸的是,有些计算机采用高位优先的存储方式,而另一些计算机却采用低位优先的存储方式。例如,IBM兼容机和Macintosh机对高位字节和低位字节的处理方法就不同。
为什么这种区别会产生影响呢?试想一下,假如用fwrite()直接把一个short类型的值按两字节存到文件或网络上,不考虑格式和是否可读,而只是存为紧凑的二进制形式,会引起什么后果呢?假如在高位优先的计算机上存入这个值,而在低位优先的计算机上读出该值(或者反过来),那么存入的是0102H(258),读出的就是0201H(513)。
解决这个问题的办法是选择一种存储(和读取)方式,并且自始至终使用这种方式,而不是按存入内存的方式来存储short或int类型的值。例如,有些标准指定了“网络字节顺序(network byte order)”,它是一种高位优先顺序(即高位字节存放在低地址中)。例如,假如s是一个short类型值而a是一个由两个char类型组成的数组,那么下面这段代码
a[0]=(s>>4)& Oxf;
a[1]=s&0xf;
将把s的值按网络字节顺序存入a的两个字节中。不管程序是运行在高位优先或低位优先的计算机上,s的值都会存成这种形式。
你可能会注重到,笔者一直没有提到哪种计算机是高位优先或低位优先的计算机。这样做是有目的的——假如可移植性是重要的,你就应该按这两种类型的计算机都能接受的方式编写程序;假如效率是重要的,通常你仍然要按这两种类型的计算机都能接受的方式编写程序。
例如,在高位优先的计算机上可以用一种更好的方法去实现上例中的那段代码,即使你使用了上例中的代码,一个好的编译程序仍然会利用那种更好的实现来产生气器代码。
注重:“big-endian"和"little-endian"这两个名称来源于Jonathan Swift所写的《格列佛游记>>(Gulliver's Travels)一书。在格列佛第三次出海时,他碰到了这样一群人,他们对煮熟了的鸡蛋的吃法争论不休:有的要先吃大头,有的要先吃小头。
“网络字节顺序”只适用于int,short和long类型。char类型的值按定义只有一字节长,因此字节顺序与它无关。对于float和double类型的值,没有一种标准的存储方式。
请参见:
10.5 什么是高位字节和低位字节?
10.6 16位和32位的数是怎样存储的?
Word教程网 | Excel教程网 | Dreamweaver教程网 | Fireworks教程网 | PPT教程网 | FLASH教程网 | PS教程网 |
HTML教程网 | DIV CSS教程网 | FLASH AS教程网 | ACCESS教程网 | SQL SERVER教程网 | C语言教程网 | JAVASCRIPT教程网 |
ASP教程网 | ASP.NET教程网 | CorelDraw教程网 |