怎样如何看待别人的评价John Carmack对于C++和C的评价

1964年John Kemeny 和Thomas Kurtz简化Fortran发明了BASIC(Beginners All-purpose Symbolic Instruction Code BASIC初学者通用指令码)语言,1970年瑞士计算机科学家Niklaus Wirth又在ALGOL68的基础上创造了Pascal语言。前者是为专入门的文科学生设计的,简单易学,至今仍然是业余爱好者的宠物;后者则是结构化程序设计语言的典范、结构优美,曾被广泛用于计算机教学;但是,它们的功能有限、灵活性不够、效率也不高,也都不适合于编写系统编程。
附注:1991年和2002年微软公司的Alan Cooper和Paul Vick分别开发出Visual Basic和Visual Basic .NET。1983年Borland公司的Anders Hejlsberg和Philippe Kahn 开发出Turbo Pascal、1985年Niklaus Wirth和苹果公司的Larry Tesler又创造了Object Pascal、1995年Borland公司的Anders Hejlsberg等人在其基础上开发出Delphi。
1970年,AT&T贝尔实验室的Ken Thompson和Dennis Ritchie等人在DEC公司的PDP-7小型机上开发出了Unix操作系统,最初的实现是用汇编语言写成的。为了使Unix操作系统具有可移植性,迫切需要一种高级语言工具。为此,(出生在美国纽约的计算机科学家)Dennis Ritchie以B语言为基础,参考了Algol68,于1972年设计出了C语言。1973年他们用C语言重写了Unix,1975年又利用C语言将Unix移植到了PDP-11上。
C语言是一种可移植的系统语言,拥有充分的控制语句和数据结构功能,包含丰富的操作符,从而能够提供强大的表达能力,可以用于许多不同的应用领域。但是,C语言并不是面向科学家和计算机业余爱好者的,而是专门为程序员设计的。
为了进行高效的系统编程,C语言提供了强大的功能和极大的灵活性。与其它高级语言相比,C语言的语法简洁、表达自由、库函数丰富。如果将编程比作造房子,则Fortran和Basic等语言就像一些已经预先造好的大预制件,使用起来简单快捷,但是灵活性差、且功能有限,只能造某些固定模式的房屋;而C语言就像一块块的小砖,使用起来虽然繁琐,但是灵活性强、而且功能无限,能够造各式各样的建筑物,不过这就要求C语言程序员具有很高的专业水平。
因此,C语言假设使用者都是计算机专家,采取的是程序员负责制。它不进行完备的类型检查,对数组越界也没有限制。为了进行高效的系统编程,C语言还提供了指针和指针运算,程序员可以随意操作全部内存,任意修改任何内容。
表达的自由性和操作的任意性,也给C语言带来了很多编程问题和安全隐患。特别是C语言的++/--运算符和指针运算,更是倍受指责。
与其它高级语言相比,C语言提供了一些低级语言特征,更面向机器。所以,也有人称C语言是介于高级语言和低级语言之间的一种中级语言。
开始的很多年,C语言没有国际标准,只有一个事实标准K&R C。直到1989年和1990年,才分别推出了ANSI C和ISO C(C89或C90);1999年ISO又推出了第2版(C99)。
不像Algol、COBOL和Ada等语言,C语言并不是政府部门或国际组织的产物,而属于个人的作品。虽然由于C语言性能优越,使用得越来越广泛,但是在最初的十几年间,C语言唯一的&标准&是1978年Brian Kemighan和Dennis Ritchie编写的《C程序设计语言》(The C Programming Language)一书,通常称其为K&R C或经典C。
该书的附录&C参考手册&(C Reference Manual)成为了C语言的实现指南,但是书中缺少对库函数标准的描述,一般以Unix实现的库函数所为事实标准。
说明:因为C语言的语法成分简单,很多基本功能(例如I/O语句)都是靠库函数来实现的。所以,C语言比其它高级语言更依赖于库函数。
4)C89/C90标准
1983年ANSI(American National Standards Institute 美国国家标准协会)设立了一个X3J11小组,着手进行C语言的标准化。并最终于1989年推出ANSI C (ANSI X3.159-1989),1990年它又成为国际标准ISO C(ISO/IEC
Programming languages & C,程序设计语言&&C),原来叫做ANSI C或ISO C,现在通常称其为C89或C90。
标准的指导原则是:
l 相信程序员;
l 不妨碍程序员做需要完成的事情;
l 让语言保持短小简单;
l 只提供一种方法来执行一种操作;
l 使程序运行速度快,即使不能保证其可移植性。(不追求定义的抽象统一,更优先考虑运行效率)
这些其实也正是C语言的设计初衷,所以ANSI/ISO的C标准,对原始的C语言修改并不多。标准C对K&R C的主要改变是,增加了函数原型(prototype),强调对函数的输入参数进行严格的类型检查;并补充定义了C语言的标准函数库。
函数原型的类型检查是指:在编译时,对调用函数的实参和函数定义时的形参的类型是否一致,进行严格的检查。目的是减少程序纠错的难度(这类问题在运行时很难查出),同时保证运行的安全和稳定性(避免函数调用栈溢出)。(这也为实现C++函数的参数型多态性提供了条件。)
u K&R C:(过时的)
power(); // 函数的前向声明
power(x, n) // 函数定义
int p = power(3) * power(3.9, 5.4); // 使用(编译可通过,运行时产生逻辑错误)
u C89/C90:(推荐的)
int power(int x, int n); // 函数声明1(函数原型)
int power(int, int); // 函数声明2(函数原型)
int power(int x, int n) // 函数定义
int p = power(3) * power(3.9, 5.4); // 使用(编译不能通过,错误:第1个调用
// 的参数太少、警告:第2个调用的参数自动转换为(3, 5))
l C89/C90对K&R C的其它改变有:
n 删除了关键字:entry(条目/入口)
n 增加了关键字:const(常型变量)、enum(枚举类型)、signed(有符号的,例如signed char)、void(空/无,可用于函数返回值和形参、通用指针类型)、volatile(易变变量,防止编译器错误的优化)
n 传递结构:允许将结构本身作为参数传递给函数(原来只允许传地址)
n 函数原型:增加了函数原型(便于编译器进行类型检查)
n 增加了预处理指令:#elif(else if)、#error(错误,强制编译停止)、#line(修改当前行号和源文件名)、#pragma(附注/编译指令,编译器定义的与实现有关的指令)
n 定义了固有宏:__LINE__(当前行号)、__FILE__(源文件名)、__DATE__(当前系统日期)、__TIME__(当前系统时间)、__STDC__(标准C版时为1)
5)C99标准
对C90的修订工作开始于1994年,在ISO C++(1998)标准推出之后,ISO又于日,推出了C语言标准的第2版:ISO/IEC
Programming languages & C(程序设计语言&&C),一般称其为C99。
(1)修订目标
C99保持了C语言的本质特性,C继续是一种短小、清晰和高效的语言。C99并没有增加新的本质特性,但是为了满足新的需要,也进行很多小的修订。
l C99主要的修订目标有三点:
n 支持国际化编程,引入了支持国际字符集Unicode的数据类型和库函数;
n 修正原有版本的明显缺点。如整数的移植方法,例如int8_t、int16_t、int32_t和int64_t等类型;
n 针对科学和工程的需要,改进计算的实用性。例如添加了复数类型和新数学函数。
(2)具体修改
l C99对C89/C90的具体修改有:
n 增加了C++的//注释风格:原来C语言之支持多行注释:/*&&*/,C99现在也识别单行注释:// &&
n 增加了关键字:inline(内联函数)、restrict(限制)、_Bool(布尔类型)、_Complex(复数)、_Imaginary(虚数)
u 内联函数(inline):链接时不是进行函数调用而是嵌入函数体代码(可减少调用的时间开销,适用于要求运行速度快的小型函数)
u restrict:只能用于指针,表明该指针是数据对象的唯一且初始的方式(不是通过指针的赋值运算另外来得的),便于编译器进行代码优化。
附注:微软公司VC扩展的restrict,是让编译器限制别名(如用typedef定义的)的使用,必须类型名完全一致(只是类型等价还不够)时,类型检验才能通过
u _Bool:布尔类型,为整数类型,一般用1(或非0)表示真、用0表示假。如果包含了C99新增加的标准库头文件stdbool.h,则可以用bool来代替_Bool,并可使用true和false,从而与标准C++兼容
u 复数和虚数类型:
l 如果包含了C99新增加的标准库头文件complex.h后,就可以用complex来代替_Complex、用imaginary来代替_Imaginary
l 有三种复数和虚数类型:float _Complex、double _Complex、long double _Complex;float _Imaginary、double _Imaginary、long double _Imaginary
l 在C99内部,是用二元数组来实现复数的,第一个数组元素为实部、第二个数组元素为虚部
l 可以用实数和(定义在complex.h中的)I来初始化一个复变量。例如:
#include &complex.h&
double complex z = 6.0 & 8.5 * I, w = 3.0, u = 4.0 * I;
C99的关键字(Keywords)(共37个)
_Imaginary
其中:黑色的为K&R C原有的关键字,绿色的为C90添加的关键字,红色的为C99新增的关键字。(C90删除了K&R C的关键字entry)
n 增加了数据类型:(unsigned) long long [int](64位整数)(对应的打印输出格式为%lld或%llu)
n 定义了可移植整数类型:因为同一整数类型,在不同字长的计算机系统中,可能位数不一样,这给移植带来了问题。因此,C99在新增加的头文件inttypes.h中定义了已有整数类型的一些别名,便于程序移植。例如:int8_t、int16_t、int32_t、int64_t,uint8_t、uint16_t、uint32_t、uint64_t;intptr_t、uintptr_t。以及表示对应类型常量的方法,例如INT8_C(128)、INT32_C(1234)。
n 增加了预定义宏:C99新加了两个预定义宏:__STDC_HOSTED__(是本机环境时为1,否则为0)和__STDC__VERSION__(=199901L时为C99,否则为C89/C90)
n 提供了一个预定义标识符:__func__,为一个代表函数名的字符串(该函数中包含有此标识符),该标识符具有函数作用域。(宏具有文件作用域)
n 增加了浮点常量的十六进制格式:p或P表示后跟二进制指数(的十进制值)。例如:0xa.1cp10 = (10 + 1/16 + 12/256) * 210 = 10352.0
n 增加了浮点数的十六进制打印格式符:%a或%A(代替十进制的%e或%E)、%La或%LA(代替十进制的%Le或%LE)
n 可指定初始化的条目:在对数组和结构进行初始化时,原来必须从头到尾顺序指定初值,最多只能省掉对尾部部分赋初值(未被初始化的条目全被置为0)。C99可以用[i] = v的方法,在花括号中为指定条目i赋初值v。例如:
int a[6] = {[5] = 123}; // 最后一个数组元素的初值为123,其余的值全为0
int days[12] = {31, 28, [4] = 31, 30, 31, [1] = 29}; // 则初值序列为31 29 0 0
// 31 30 31 0 0 0 0 0
n 支持变长数组(VLA = Variable-Length array):原来的C语言(包括C++)要求数组定义中的大小必须是整数常量[表达式],而C99允许使用变量。例如:
#define SIZE 12
int a1[5], a2{SIZE}; // C89可以
float a3[n], a4[m][n]; // C89不允许,C99可以
注意:这里的变长,不是说数组的大小可以随意改变;而是指在定义时,数组的大小可以是变量。一旦定义完成,数组的大小就已固定,不允许再进行改变。
n 复合文字(compound literal混合直接量):可以用于定义无名数组、给函数传递数组和结构常量参数、给其他数组和结构赋初值等。例如:
int *pt = (int []) {53, 16, 88}; // 定义无名数组
int sum(int a[], int n); // 函数原型
int total = sum((int []) {4, 3, 5, 2}, 4); // 给函数传递数组常量参数
struct book { // 定义结构
char tutle[41];
char author[31];
// 定义结构变量
bk = (struct book) {&C Programming&, &Dennis Ritchie&, 9.8}; // 给结构赋初值
n 允许在代码块的任何地方定义变量:原来C语言的块变量定义,必须位于块的开始处(在任何可执行代码之前)。C99允许在代码块的任何地方(包括控制语句部分)定义变量(~C++),例如:for(int i = 0; i & 10; i++) {&&}
n 旧关键字的新位置:C99允许将类型限定词(如const、volatile、restrict)和存储限定词(如auto、register、static)放在函数原型和函数头形参的方括号内。例如:
void f(int *const a1, int *restrict a2, double static a3[20]); // 老风格
void f(int a1[const], int a2[restrict], double a3[static 20]); // 新风格
n 弹性数组成员(flexible array member):C99允许在结构的最后定义一个大小可伸缩的弹性数组成员,可以用于结构指针,根据允许情况来动态分配内存。但是操作就像它本来就有这么多数组元素似的,增加了编程的灵活性和源码的可读性。例如:
strtuct flex {
double scores[]; // 弹性数组成员
struct flex *
pf = malloc(sizeof(struct flex) + n * sizeof(double));
pf-&count =
double sum = 0;
for (int i = 0; i & i++) {
fstrm && pf-&scores[i];
sum += pf-&scores[i]
pf-&average = sum /
n 编译指令:在C99中定义了如下三个标准编译指令:
#pragma STDC FP_CONTRACT on-off-switch // 允许或禁止浮点表达式压缩
#pragma STDC FENV_ACCESS on-off-switch // 通知是否访问浮点环境
#pragma STDC CX_LIMITED_RANGE on-off-switch // 通知复数是否范围有限
其中的on-off-switch取值为ON、OFF和DEFAULT之一。
n C99还新提供了_Pragma预处理运算符,可以将字符串转换成常规的编译指令。例如:
_Pragma(&use_bool true false&)
#pragma use_bool true false
(3)新增标准库
l C99的标准库和头文件
n 标准头文件:&assert.h&、&complex.h&、&ctype.h&、&errno.h&、&fenv.h&、&float.h&、&inttypes.h&、&iso646.h&、&limits.h&、&locale.h&、&math.h&、&setjmp.h&、&signal.h&、
&stdarg.h&、&stdbool.h&、&stddef.h&、&stdint.h&、&stdio.h&、&stdlib.h&、&string.h&、&tgmath.h&、&time.h&、&wchar.h&、&wctype.h&
n 新增加的头文件:在上面的标准头文件中,C99新增加的为:&complex.h&、&fenv.h&、&inttypes.h&、&iso646.h&、&stdbool.h&、&wchar.h&、&wctype.h&。下面将逐个加以简单介绍
n complex.h:定义了宏complex、imaginary和I,定义了各种数学函数(与不同数学函数相比,增加的前导字符c表示复数,尾部字符f和l分别表示float和long double类型,没有尾部字符的为double型),例如:
double complex ccos(double complex z);
float complex ccosf(float complex z);
long double complex ccosl(long double complex z);
C99中的复数处理函数(省略了f和l版)
carg(double complex z);
返回z的相位角/辐角(弧度)
cimag(double complex z);
返回z的虚部(实数形式)
complex conj(double complex z);
返回z的共轭复数
complex cproj(double complex z);
返回z在黎曼域上的投影
creal(double complex z);
返回z的实部(实数形式)
注意:该库VC05不支持
n fenv.h:提供对浮点数环境的访问和控制
u 开启/关闭对浮点环境的访问:#pragma STDC FENV_ACCESS ON / OFF
u 浮点环境类型:fenv_t(整个浮点环境)、fexcept_t(浮点状态标志的集合)
u 标准的浮点异常和控制宏:
FE_DIVBYZERO
抛出被0除异常
FE_INEXACT
抛出不精确值异常
FE_INVALID
抛出非法值异常
FE_OVERFLOW
抛出上溢异常
FE_UNDERFLOW
抛出下溢异常
FE_ALL_EXCEPT
抛出位异常或实现所支持的所有浮点异常
FE_DOWNWARD
FE_TONEAREST
FE_TOWARDZERO
FE_DFL_ENV
默认环境(const fevn_t*类型)
feclearexcept(int excepts);
清除异常excepts
void fegetexceptflag(fexcept_t *flagp, int
将excepts异常的标志存储到flagp中
void feraiseexcept(int excepts);
抛出excepts异常
void fesetexceptflag(const fexcept_t
*flagp, int excepts);
将异常标志excepts设置为flagp状态
int fetestexcept(int excepts);
返回excepts指定查询状态的标志位
int fegetround(void);
返回当前的舍入方向
int fesetround(int round);
将舍入方向设为round,成功返回0
void fegetenv(fenv_t *envp);
将当前环境存入envp
int feholdexcept(fenv_t *envp);
将当前环境存入envp,清除浮点状态标志,成功返回0
void fesetenv(const fenv_t *envp);
建立envp表示的环境
void feupdateenv(const fenv_t *envp);
建立envp表示的环境,并抛出自动存储的浮点异常
注意:该库VC05也不支持
n inttypes.h:C语言中的同一整数类型,在不同字长的计算机系统中,可能位数不一样,这给移植带来了问题。因此,C99在新增加的头文件inttypes.h中定义了可移植的整数类型。
固定长度类型
printf说明符
scanf说明符
UINT16_MAX
UINT32_MAX
UINT64_MAX
最小长度类型
printf说明符
scanf说明符
int_least8_t
PRILEASTd8
SCNLEASTd8
INT_LEAST8_MIN
INT_LEAST8_MAX
int_least16_t
PRILEASTd16
SCNLEASTd16
INT_LEAST16_MIN
INT_LEAST16_MAX
int_least32_t
PRILEASTd32
SCNLEASTd32
INT_LEAST32_MIN
INT_LEAST32_MAX
int_least64_t
PRILEASTd64
SCNLEASTd64
INT_LEAST64_MIN
INT_LEAST64_MAX
uint_least8_t
PRILEASTu8
SCNLEASTu8
UINT_LEAST8_MAX
uint_least16_t
PRILEASTu16
SCNLEASTu16
UINT_LEAST16_MAX
uint_least32_t
PRILEASTu32
SCNLEASTu32
UINT_LEAST32_MAX
uint_least64_t
PRILEASTu64
SCNLEASTu64
UINT_LEAST64_MAX
最快的最小长度类型
printf说明符
scanf说明符
int_fast8_t
INT_FAST8_MIN
INT_FAST8_MAX
int_fast16_t
PRIFASTd16
SCNFASTd16
INT_FAST16_MIN
INT_FAST16_MAX
int_fast32_t
PRIFASTd32
SCNFASTd32
INT_FAST32_MIN
INT_FAST32_MAX
int_fast64_t
PRIFASTd64
SCNFASTd64
INT_FAST64_MIN
INT_FAST64_MAX
uint_fast8_t
UINT_FAST8_MAX
uint_fast16_t
PRIFASTu16
SCNFASTu16
UINT_FAST16_MAX
uint_fast32_t
PRIFASTu32
SCNFASTu32
UINT_FAST32_MAX
uint_fast64_t
PRIFASTu64
SCNFASTu64
UINT_FAST64_MAX
最大长度类型
printf说明符
scanf说明符
INTMAX_MIN
INTMAX_MAX
UINTMAX_MAX
可保存指针值的整数类型
printf说明符
scanf说明符
INTPTR_MIN
INTPTR_MAX
UINTPTR_MAX
注意:该库VC05也不支持。但是微软在VC中定义了扩展的C++关键字:__int8、__int16、__int32和__int64;在Windows API定义了INT32、INT64、UINT32和UINT64等数据类型;在.NET框架也定义了Int16、Int32、Int64、UInt16、UInt32和UInt64等结构类型。
n iso646.h:定义了运算符的替代字符串
注意:该C库VC05支持
n stdbool.h:定义了bool(_Bool)、false(0)和true(1)等宏。
注意:该C库VC05也不支持。但是C++标准支持,它们都是C++的关键字。
n wchar.h:定义了扩展的多字节字符和宽字符工具:(参见wchar.doc,该C库VC05支持)
u 数据类型:
l wchar_t:可表示本地环境所支持的最大扩展字符集的一种整数类型,在VC05中定义为unsigned short(2B)
l wint_t:可表示最大扩展字符集任何值以及其他值的一种整数类型,在VC05中定义为int(4B)
l size_t:由sizeof返回的整数值类型,在VC05中定义为unsigned int(4B)(在Win64中定义为unsigned __int64)
l mbstate_t:为一种非数组的对象类型,用于保存多字节字符与宽字符之间转换所需状态信息。在VC05中定义为int(4B)
l struct tm:用来保存日历时间成分的结构类型,至少应该包含下列成员:
int tm_ // seconds after the minute & [0, 60]
int tm_ // minutes after the hour & [0, 59]
int tm_ // hours since midnight & [0, 23]
int tm_ // day of the month & [1, 31]
int tm_ // months since January & [0, 11]
int tm_ // years since 1900
int tm_ // days since Sunday & [0, 6]
int tm_ // days since January 1 & [0, 365]
int tm_ // Daylight Saving Time flag
在VC05中定义也为:
struct tm {
int tm_ /* seconds after the minute - [0,59] */
int tm_ /* minutes after the hour - [0,59] */
int tm_ /* hours since midnight - [0,23] */
int tm_ /* day of the month - [1,31] */
int tm_ /* months since January - [0,11] */
int tm_ /* years since 1900 */
int tm_ /* days since Sunday - [0,6] */
int tm_ /* days since January 1 - [0,365] */
int tm_ /* daylight savings time flag */
u 符号常量宏:
l NULL(空指针,VC05中定义为((void *)0))
l WCHAR_MAX(wchar_t的最大值,VC中定义为0xFFFF[65535])
l WCHAR_MIN(wchar_t的最小值,VC05中定义为0)
l WEOF(宽字符文件的结尾,是EOF的宽字符表示,在VC05中定义为(wint_t)(0xFFFF)[65535])
u 宽字符I/O函数:
l I/O函数:(字符和串格式符从%c和%s改为%lc和%ls)
int fwprintf(FILE * stream, const wchar_t * format, ...);
int fwscanf(FILE * stream, const wchar_t * format, ...);
int swprintf(wchar_t * s, size_t n, const wchar_t * format, ...);
int swscanf(const wchar_t * s, const wchar_t * format, ...);
int vfwprintf(FILE * stream, const wchar_t * format, va_list arg);
int vfwscanf(FILE * stream, const wchar_t * format, va_list arg);
int vswprintf(wchar_t * s, size_t n, const wchar_t * format, va_list arg);
int vswscanf(const wchar_t * s, const wchar_t * format, va_list arg);
int vwprintf(const wchar_t * format, va_list arg);
int vwscanf(FILE * stream, const wchar_t * format, va_list arg);
int wprintf(const wchar_t * format, ...);
int wscanf(const wchar_t * format, ...);
wint_t fgetwc(FILE *stream);
wchar_t *fgetws(wchar_t * s, int n, FILE * stream);
wint_t fputwc(wchar_t c, FILE *stream);
int fputws(const wchar_t * s, FILE * stream);
int fwide(FILE *stream, int mode);
wint_t getwc(FILE *stream);
wint_t getwchar(void);
wint_t putwc(wchar_t c, FILE *stream);
wint_t putwchar(wchar_t c);
wint_t ungetwc(wint_t c, FILE *stream);
l 字符串工具:
double wcstod(const wchar_t * nptr, wchar_t ** endptr);
float wcstof(const wchar_t * nptr, wchar_t ** endptr);
long double wcstold(const wchar_t * nptr, wchar_t ** endptr);
long int wcstol(const wchar_t * nptr, wchar_t ** endptr, int base);
long long int wcstoll(const wchar_t * nptr, wchar_t ** endptr, int base);
unsigned long int wcstoul(const wchar_t * nptr, wchar_t ** endptr, int base);
unsigned long long int wcstoull(const wchar_t * nptr, wchar_t ** endptr, int base);
wchar_t *wcscpy(wchar_t * s1, const wchar_t * s2);
wchar_t *wcsncpy(wchar_t * s1, const wchar_t * s2, size_t n);
wchar_t *wcscat(wchar_t * s1, const wchar_t * s2);
wchar_t *wcsncat(wchar_t * s1, const wchar_t * s2, size_t n);
int wcscmp(const wchar_t *s1, const wchar_t *s2);
int wcscoll(const wchar_t *s1, const wchar_t *s2);
int wcsncmp(const wchar_t *s1, const wchar_t *s2, size_t n);
size_t wcsxfrm(wchar_t * s1, const wchar_t * s2, size_t n);
wchar_t *wcschr(const wchar_t *s, wchar_t c);
size_t wcscspn(const wchar_t *s1, const wchar_t *s2);
size_t wcslen(const wchar_t *s);
wchar_t *wcspbrk(const wchar_t *s1, const wchar_t *s2);
wchar_t *wcsrchr(const wchar_t *s, wchar_t c);
size_t wcsspn(const wchar_t *s1, const wchar_t *s2);
wchar_t *wcsstr(const wchar_t *s1, const wchar_t *s2);
wchar_t *wcstok(wchar_t * s1, const wchar_t * s2, wchar_t ** ptr);
wchar_t *wmemchr(const wchar_t *s, wchar_t c, size_t n);
int wmemcmp(wchar_t * s1, const wchar_t * s2, size_t n);
wchar_t *wmemcpy(wchar_t * s1, const wchar_t * s2, size_t n);
wchar_t *wmemmove(wchar_t *s1, const wchar_t *s2, size_t n);
wchar_t *wmemset(wchar_t *s, wchar_t c, size_t n);
size_t wcsftime(wchar_t *s, size_t maxsize, const wchar_t *format, const struct tm *timeptr);
size_t wcsfxtime(wchar_t *s, size_t maxsize, const wchar_t *format, const struct tmx *timeptr);
l 转换函数:
wint_t btowc(int c);
int wctob(wint_t c);
int mbsinit(const mbstate_t *ps);
size_t mbrlen(const char * s, size_t n, mbstate_t * ps);
size_t mbrtowc(wchar_t * pwc, const char * s, size_t n, mbstate_t * ps);
size_t wcrtomb(char * s, wchar_t wc, mbstate_t * ps);
size_t mbsrtowcs(wchar_t * dst, const char ** src, size_t len, mbstate_t * ps);
size_t wcsrtombs(char * dst, const wchar_t ** src, size_t len, mbstate_t * ps);
n wctype.h:提供与ctype.h类似的宽字符函数。(也参见wchar.doc,该C库VC05也支持)
l wint_t:可保存扩展字符值的一种整数类型,VC05中定义为unsigned short(2B)
l wctrans_t:表示特定字符映射的一种标量类型,VC05中定义为wchar_t(2B)
l wctype_t:表示字符分类的一种标量类型,VC05中也定义为unsigned short(2B)
u 符号常量宏:
l WEOF:宽字符输入的文件结尾,VC05中定义为(wint_t)(0xFFFF) [65535]
l 分类函数:
int iswalnum(wint_t wc);
int iswalpha(wint_t wc);
int iswcntrl(wint_t wc);
int iswdigit(wint_t wc);
int iswgraph(wint_t wc);
int iswlower(wint_t wc);
int iswprint(wint_t wc);
int iswpunct(wint_t wc);
int iswspace(wint_t wc);
int iswupper(wint_t wc);
int iswxdigit(wint_t wc);
l 可扩展分类函数:
int iswctype(wint_t wc, wctype_t desc);
wctype_t wctype(const char *property);
l 转换函数:
wint_t towlower(wint_t wc);
wint_t towupper(wint_t wc);
wint_t towctrans(wint_t wc, wctrans_t desc);
wctrans_t wctrans(const char *property);
(4)数学改进
除了上面以及讲过的新增关键字_Complex(复数)和_Imaginary(虚数)、float和long double版的数学函数、以及复数运算的标准库外。C99对数学库也进行了许多修改,增加了两个数据类型,并添加了大量新的数学函数。
l math.h:除了上面这些新增加的库和头文件外,为了支持IEC (Binary floating-point arithmetic for microprocessor systems微处理器系统的二进制浮点运算)浮点运算标准,C99还对数学库进行了如下扩展:
n float_t和double_t类型:是C99新增加的分别进行float和double运算最快的的类型。(位数:double_t&float_t、float_t&float、double_t&double)
n float和long double版函数:原来的很多数学函数只有double版,C99新增加了float版和long double版的数学函数。做法是:改变输入参数和返回值,并在函数名的尾部,增加一个字符f或l,来分别表示float或long double类型(没有尾部字符的为原来的double型)。例如:
double cos (double x);
float cosf (float x);
long double cosl (long double x);
n 新符号常量:
C99新增加的数学符号常量
最大的float值
最大的long double值
FP_INFINITE
浮点无穷大分类号
非浮点数分类号
正常浮点数分类号
FP_SUBNORMAL
精度降低的浮点数分类号
浮点数0的分类号
FP_FAST_FMA
速度&double操作数的乘法和加法的函数fma
FP_FAST_FMAF
速度&float操作数的乘法和加法的函数fmaf
FP_FAST_FMAL
速度&long double操作数的乘法和加法的函数fmal
表示ilogb(0)函数返回值的整数常理表达式
FP_ILOGBNAN
表示ilogb(NAN)函数返回值的整数常理表达式
MATH_ERRNO
MATH_ERREXCEPT
MATH_ERRHANDLING
= MATH_ERRNO、MATH_ERREXCEPT或
MATH_ERRNO | MATH_ERREXCEPT
n 新函数:
C99新增加的数学函数
(float和long double版数学函数未写出)
int fpclassify(real-floating x);
返回x的浮点数分类值的宏
int isfinite(real-floating x);
x有穷时返回非0值的宏
int isinf(real-floating x);
x无穷时返回非0值的宏
int isnan(real-floating x);
x非数时返回非0值的宏
int isnormal(real-floating x);
x为正常数时返回非0值的宏
int signbit(real-floating x);
x为负数时返回非0值的宏
double exp2(double x);
double expm1(double x);
int ilogb(double x);
返回x(以FLT_RADIX为基数)的指数int值
double log1p(double x);
double log2(double x);
double logb(double x);
返回x(以FLT_RADIX为基数)的指数
double scalbn(double x, int n);
返回x*FLT_RADIXn
double scalbln(double x, long n);
返回x*FLT_RADIXn
double cbrt(double x);
double hypot(double x, double y);
double erf(double x);
返回x的误差函数
double erfc(double x);
返回x的补余误差函数
double lgamma(double x);
double tgamma(double x);
double nearbyint(double x);
(使用浮点环境指定的舍入方向)将x舍入到最近的整数(double值)
double rint(double x);
似nearbyint,但是抛出inexact异常
long lrint(double x);
(使用浮点环境指定的舍入方向)将x舍入到最近的整数(long值)
long long llrint(double x);
(使用浮点环境指定的舍入方向)将x舍入到最近的整数(long long值)
double round(double x);
将x舍入到最近的整数(四舍五入)(double值)
long lround(double x);
将x舍入到最近的整数(四舍五入)(long值)
long long llround(double x);
将x舍入到最近的整数(四舍五入)(long long值)
double trunc(double x);
double remainder(double x, double y);
返回x除以y的余数
double remquo(double x, double y, int
返回值同remainder,将x/y取整后放入quo
double copysign(double x, double y);
sign(x)*|y|
double nan(const char *tagp);
返回NaN类型的double表示
double nextafter(double x, double y);
y=x时返回x、y&x时返回比x大的下一个double值、y&x时返回比x小的下一个double值
double fdim(double x, double y);
double fmax(double x, double y);
double fmin(double x, double y);
double fma(double x, double y, double z);
int isgreater(real-floating x,
real-floating y);
返回x&y的宏
int isgreaterequal(real-floating x,
real-floating y);
返回x&=y的宏
int isless(real-floating x, real-floating
返回x&y的宏
int islessequal(real-floating x,
real-floating y);
返回x&=y的宏
int islessgreater(real-floating x,
real-floating y);
返回x&y || x&y的宏
int isunordered(real-floating x,
real-floating y);
x和y中至少一个为NaN时返回1,否则0
注意:该库VC05也不支持。但是VC05支持原数学函数的float和long double版。
(5)扩展字符支持
除了上面讲过的wcahr_t类型定义和新增加的两个宽字符标准库(&wchar.h&、&wctype.h&)外,C99中还有其他对扩展字符支持方面。
l 其它扩展字符支持:因为C语言最初并不是为国际字符集设计的,所以除了上面的wchar.h和wctype.h库外,还有如下一些扩展字符支持的方面:
n 三元字符(trigraph):考虑到有些键盘并不能提供C中所使用的全部符号,早在C89中就已经定义了一些三元字符序列,作为这些符号的可选表示:(为C语言的保留字,但不是关键字,VC05支持)
三元字符在任何地方都是同样的含义,即使在字符串中也是如此。
n 二元字符(digraph):由于三元符号太笨拙,C99新增加了二元字符:(也为C语言的保留字,但不是关键字,不过VC05不支持)
与三元字符不同,二元字符在字符串中没有特别意义(视作原来的两个字符)。
n UCN(Universal-Character-Name通用字符名):C99允许使用ISO/IEC 10646(Unicode)国际字符集中的字符(包括汉字)作为标识符的一部分,但是扩展字符中的数字字符也不能作为标识符的起始字符。可以使用/u或/U开头的4个(16位)或8个(32位)十六进制数字(/uhhhh、/UHHHH、/uhhhhhhhh、/UHHHHHHHH)来表示扩展字符。(VC05支持[作为C++标准的一部分])。例如:
wchar_t buf[80];
wchar_t ch1 = '变', ch2 = L'变'; // ch1为多字节字符,ch2为宽字符
int 变量1 = 25, /u53D8/u91CF2 = 30; // 如果变量名后不加1和2,
// 则报变量重名的错误
变量1 *= /u53D8/u91CF2;
swprintf(buf, 80, L&%lc = 0x%X = 0x%X, %lc = 0x%X = 0x%X&,
ch2, ch1, ch2, L'量', '量', L'量');
pDC-&TextOut(10, 10, buf);
swprintf(buf, 80, L&变量1 = %d, /u53D8/u91CF2 = %d&,
变量1, /u53D8/u91CF2);
pDC-&TextOut(10, 40, buf);
输出结果为:(&变量&的GB码为B1E4 C1BF、Unicode码为53D8 91CF)
变=0xB1E4=0x53D8, 量=0xC1BF=91CF
变量1=750, 变量2=30
n 前缀与修识符:宽字符常量和宽字符串常量,可以用L前缀来表示。在格式化I/O函数中,可以用%lc和%ls修识符来显示宽字符及其串数据
6)C和C++的差别
虽然C++是C的超集,但是它们之间还是存在细小的差别,特别是C99增加的新特性中,有许多当前的C++标准还不支持。下面列出一些C和C++的差别:
l 函数原型
在C++中是必须的,在C中(虽然被极力推荐,但仍然)是可选的。例如:
int myfun(); // 在C中被认为是前向声明
// 在C++中等价于函数原型:int myfun(void);
int main() {
myfun(20,45); // 在C++会报错(函数不是两个输入参数)
int myfun(int a, int b) {&&} // 在C++被认为是另一个函数
l 强制转换
在C中,自动转换似乎可以无处不在。例如,可以不经过强制转换,直接将void *型的变量或表达式赋值给其他指针类型的变量。但是这样做在C++中确是不被允许的,而必须使用显式的强制转换。这是因为,太任意的自动类型转换,会造成很多很难查出的程序问题。所以,C++的新规定,是出于程序安全和故障排查的考虑而制定的。
l char常量
在C中char常量被处理为int类型(4B),而在C++则被处理为char类型(1B)。例如:
char ch = &A&;
在C中常量A被存储为一个int值,但变量ch则只占1个字节;而在C++中常量A和变量ch都只占1个字节。又例如:
int x = &ABCD&;
在C中是可以的(变量x的值为),在C++中则是非法的(但在VC05中可以)。而
char c = &ABCD&;
在C和C++中都是可以的,不过会发出截断警告(变量c的值为D)
l const修识符
n 在缺省情况下,全局的常型变量,即在函数体外部声明的,例如:
const double PI = 3.14159;
在C中具有外部链接(只能在一个文件中定义,在其它文件中,必须用extern进行引用声明后,才能被使用);在C++中则具有内部链接(可以定义在头文件中定义,使每个包含该头文件的代码文件,都有该变量的一个拷贝)。
n 可以在C中,通过将全局的常型变量声明为静态的,使其变成内部链接的:
static const double PI = 3.14159;
也可以在C++中,使用extern关键字使全局的常型变量变成外部的。
n 在C++中常型变量可以用来声明数组的大小,但是在C中不行。例如:
const int SIZE = 100;
double a[SIZE]; // 在C++中等价于double a[100];
// 在C中则创建了一个变长数组,还需要给它分配空间
n 在C++中可以使用一个已经初始化了的常型变量给另一个常型变量赋值,但在C中这样做是非法的。例如:
const double RATE = 0.5;
const double STEP = 24.0;
const double LEVEL = RATE * STEP; // 在C++中合法,在C中非法
l 结构和联合
n 声明了一个带有标记(tag)的结构或联合之后,在C++可以直接用此标记作为类型名,但是在C中则不行(必须前面带有struct关键字才可以)。例如:
struct point {
struct point p1; // 在C和C++中都可以
point p2; // 在C++中可以,但在C中不行
n 嵌套的结构在C中可以直接引用,在C++中则必须采用定位符。例如:
struct box {
struct point {}
// 在C和C++中都可以
struct point dot1; // 在C中可以,但在C++中不行
box::point dot2; // 在C++中可以,但在C中不行
n 与结构类似,在C++允许声明枚举变量时省略enum关键字,但是C不行。例如:
enum season {spring, summer, autumn, winter};
season ssn = // 在C中非法,在C++中合法
n 在枚举的使用中,C++比C更严格。在C++中,不允许把整数值赋给枚举变量,也不能递增一个枚举变量。例如:
enum season {spring, summer, autumn, winter};
ssn = // 在C和C++中都可以
ssn = 2; // 在C中会发出警告,但在C++中是一个错误
ssn = (enum season)1; // 在C和C++中都可以
ssn++; // 在C中可以,但在C++中是一个错误
l 指向void的指针
在C++中不能把指向void的指针,不经显示转换,而直接赋給其它类型的指针。但是在C中则可以。例如:
int a[4] = {1, 2, 3, 4};
pv = // 在C和C++中都可以
pi = // 在C中可以,但在C++中非法
pi = (int *) // 在C和C++中都可以
l 布尔类型:C++中的布尔类型bool和值true与false都是关键字。在C99中_Bool类型是关键字,但是bool和true与false却是在stdbool.h中定义的typedef类型和符号常量宏。
l 可选的拼写:and、or和not_eq等在C++中都是关键字;但在C99中是在iso646.h头文件中定义的宏。
l 宽字符类型:wchar_t在C++是关键字;但在C99中是在wchar.h等头文件中定义的typedef类型。
l 复数类型:在C99中可以通过关键字_Complex和_Imaginary来使用内置的复数类型。但是C++中是通过头文件complex中的模版类来使用复数类型的。(在C中也可以通过complex.h来使用各种复函数)
l 内联函数:与全局常型变量类似,C99的内联函数默认是外部链接的,而C++的内联函数则默认是内部链接的。在C中还允许混合使用函数的内联和外联,但是在C++中是不允许的。
l 标准C++中目前所没有的C99特性:
n 指定初始化条目;
n 复合初始化条目;
n 受限指针;
n 变长数组;
n 弹性数组成员;
n long long和unsigned long long类型;(VC05支持)
n 可移植的整数类型;
n 通用字符名;(VC05支持)
n 附加的数学库函数;
n 通过fenv.h访问浮点环境;
n 若干预定义的标识符,如__func__;
n 具有可变数目的参数宏。
7)参考文献
l Stephen Prata(云巅工作室译). C Primer Plus(第五版)中文版. 人民邮电出版社,2005. 16开/626页/60元。
Programming languages & C(C99.pdf)
l ISO/IEC 9899:TC2()Programming languages & C(Committee Draft)(ISO C CD
N1124.pdf)
以上就是C与C++的全文介绍,希望对您学习和使用C++有所帮助.
这些内容可能对你也有帮助
无相关信息
更多可查看c++编程列表页。
猜您也会喜欢这些文章

我要回帖

更多关于 john carmack 名言 的文章

 

随机推荐