50年C语言藏着俩“老伙计”:C89和C99到底差在哪?看完秒懂!

50年C语言藏着俩“老伙计”:C89和C99到底差在哪?看完秒懂!

你敢信吗?已经50多岁的C语言,至今还是编程界的“常青树”——大学课堂必教,嵌入式开发必备,江湖地位稳如泰山。但你知道吗?这位“老伙计”其实有两个影响深远的“版本”:C89和C99。别看只差了个数字,俩兄弟的“脾气”和“本事”可差得不少。今天咱们就来唠唠,这俩标准到底有啥不一样,保证说得明明白白,看完你也能当“C语言版本通”。

先聊聊C语言的“成长档案”

要讲清C89和C99的区别,得先翻翻C语言的“户口本”。

1983年,美国国家标准协会(ANSI)觉得C语言太“野”了,各家编译器实现得乱七八糟,于是组了个委员会给它定规矩。这规矩1989年正式发布,就是咱们说的C89(也叫ANSI C)。

没过多久,1990年,国际标准化组织(ISO)看中了这个规矩,稍作调整后当成了国际标准,起名C90。所以C89和C90其实是“同一个人穿了两件马甲”,平时大家更爱叫C89。

到了1999年,ISO又给C语言更新了一版“说明书”,也就是C99。后来2011年还有个C11,但目前用得最广的还是C99,而且它还能兼容C89——就像新手机能装老软件,但功能更全。

C89和C99的“技能差异”,看完直呼“原来如此”

别看都是C语言,俩版本的“技能包”差得可不少。咱们挑最实用的来讲:

1. 数组:C99玩出了“新花样”

可变长数组:终于能“临场定大小”了
C89里,数组大小得提前“说好”,比如int arr[10],数字10必须是确定的。要是想让数组大小“看情况定”(比如根据用户输入的数值),门儿都没有。

但C99说:“这有啥难的?”它允许数组的大小用“运行时才知道的整数”来定,比如int n; scanf("%d", &n); int arr[n]——这种数组叫“可变长数组”。不过有俩小规矩:只能在函数内部用(局部数组),而且一旦确定大小,整个“生命周期”里就不能改了(不是能随时变大变小的动态数组哦)。

给数组“贴标签”:告诉编译器它的“脾气”
C99里,函数参数里的数组声明可以加些“备注”了。比如void func(int arr[static 5]),加个static,意思是“这数组至少有5个元素,编译器你放心用”;还能加restrict(这个指针是访问数组的“独苗”,没别人碰)、const(指针死死指着这个数组,不挪窝)。这些“标签”能帮编译器更聪明地优化代码。

2. 单行注释:终于能“随手记”了

C89时代,注释只能用/* ... */这种“框框”,哪怕只想注释一句话,也得前后“封箱”,比如:
/* 这是一句注释 */

C99大手一挥:“学C++搞个简单的!”于是引入了//单行注释,想注释啥直接写在后面,清爽得很:
// 这是一句注释,写完直接换行,多方便
从此程序员再也不用为“少个星号”调试半天了。

3. 变量声明:终于能“哪里用哪里声明”

C89有个“怪癖”:变量必须在代码块的最开头声明,比如:
int i; // 先声明 for(i=0; i<10; i++){ ... } // 再用

C99觉得这太啰嗦了:“用的时候再声明不行吗?”于是允许在for循环里直接定义变量:
for(int i=0; i<10; i++){ ... }
变量i只在这个循环里“上班”,循环结束就“下班”,不用占额外地方,干净又省心。

4. 复合赋值:临时数组“用完就扔”

C89里,想给指针指个临时数组,得先声明再赋值:
double arr[] = {1.1, 2.2, 3.3}; double *fp = arr;

C99简化了步骤:直接在赋值时“当场造一个数组”,用完自动“回收”:
double *fp = (double[]) {1.1, 2.2, 3.3};
这种“临时数组”在函数里用特别方便,不用操心后续清理。

5. 指定初始化:想给谁赋值就给谁

C89初始化数组或结构体,得按顺序来,漏了就默认0。比如初始化数组int x[10],想只给第0个和第5个赋值,只能写成:
int x[10] = {10, 0, 0, 0, 0, 30}; // 中间的0不能少

C99说:“直接点名不就完了?”于是支持“指定初始化”:
int x[10] = {[0] = 10, [5] = 30}; // 想给谁赋就给谁,其他不管

结构体也一样。比如有个结构体struct example{int k, m, n;},C89得按k、m、n的顺序赋值,C99可以直接点名:
struct example obj = {m=10, n=200}; // 只给m和n赋值,k不管
顺序随便换,想赋哪个赋哪个,简直是“懒人福音”。

6. printf/scanf:功能更“能打”了

C99给这对“输入输出兄弟”加了不少新技能:

  • 支持long long int(64位整数),用ll当“标签”,比如printf("%lld", 1234567890123LL);
  • 支持char类型的输入输出,用hh当“标签”,比如scanf("%hhd", &c);(专门读char)
  • 能输出十六进制浮点数,用aA,比如printf("%a", 3.14);会输出类似0x1.91eb85p+1的格式,给底层开发省了不少事。

7. 新增了一堆“好用的库”

C89的标准库就像个“基础工具箱”,C99直接给它升级成了“全能工具间”,新增了好几个头文件:

  • <complex.h>:专门处理复数(比如3+4i这种),搞数学计算方便多了;
  • <stdbool.h>:终于有了bool类型(布尔值,非0即1),还定义了truefalse,不用再自己#define TRUE 1了;
  • <stdint.h>:定义了一堆“精确长度”的整数类型,比如int16_t(正好16位)、int32_t(正好32位),写跨平台代码不用再猜“int到底是几位”了;
  • 还有<fenv.h>(控制浮点运算环境)、<tgmath.h>(通用浮点函数)等,给专业开发加了不少“buff”。

8. 其他“细节优化”

  • __func__标识符:每个函数里都能直接用__func__,它会自动变成当前函数的名字,调试时打印函数名超方便;
  • 更宽松的嵌套限制:C89里函数嵌套最多15层,C99放宽到127层;条件语句嵌套从8层放宽到63层,写复杂逻辑不用再“卡层数”了;
  • 取消“隐式int”:C89允许偷懒不写返回值类型(默认是int),比如func(){...},C99说“不行,必须写明int func(){...}”,规范多了;
  • 新增整数类型:除了long long int,还有int_least16_t(至少16位)、int_fast32_t(运算最快的至少32位整数)等,给不同场景定制了“专属类型”。

总结一下:C89和C99,该选哪个?

简单说,C99就是C89的“升级版”——保留了老功能,加了一堆新技能,更灵活、更强大。现在大部分编译器(比如GCC、Clang)都支持C99,甚至很多新项目直接用C99写。

当然,要是维护老代码,可能还得跟C89打交道。但不管咋说,搞懂这俩的区别,以后看代码、写代码都能心里有数,再也不怕被“版本差异”坑啦~

怎么样,50岁的C语言,这两个“版本”的故事是不是挺有意思?下次再有人问你C89和C99的区别,直接把这篇甩给他就行!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值