社区编辑申请
注册/登录
C语言为什么不检查数组下标
开发 前端
C语言的设计目标:提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

引言

最近在查一个bug,查到最后发现是数组越界导致的。数组只有30个字节,代码却向这个数组填充了35个数据,这个bug还是偶现的,查到它确实废了一番功夫。我就突然想到:C语言为什么不检查数组下标呢???先来个demo验证下。

#include<stdio.h>
#include<stdlib.h>
int main()
{
int data[5]={0};
for(int i=0;i<8;++i)
{
printf("%d ",data[i]);
}
printf("\n");

return 0;
}

结果显示,C语言还真的不检查数组的下标。不仅没有报错,而且运行正常。

思考

这就让我陷入了思考,C语言为什么不检查下标呢?想上文这么简单的,data数据组就5个数据,编译器是知道的,为什么是访问第8个数据时,编译器来个报错也没有呢?我想到了之前的文章《​​指针与数组​​》中有如下示例代码:

void main()
{
int data[4] = {0, 1, 2, 3};
int *p;
p = data +2;
printf("p[-1] is %d\n",p[-1]);
printf("*(p-1) is %d\n",*(p-1));
}

运行结果如下:

不仅可以编译通过,还能正确的输出结果为1。这表明,C的下标引用和间接访问表达式是一样的。

这让我突然意识到,数组的这些特性,如数组名本质上是一个常量指针(不懂的同学看之前的推文《​​指针与数组​​》)C语言很难检查下标合法性的。

如果C语言检查数组是否越界,因为当数组出现在表达式中的时候,它会立刻被解读成指针。此外,使用其他的指针变量也可以指向数组的任意元素,并且这个指针可以随意进行加减运算。引用数组元素的时候,虽然你可以写成a[i],但是它只不过是*(a+i)的一种表达,C语言本身的语法是无法检查的,只能通过编译器检查。

那么编译器将加入额外的代码用于检测数组是否越界,C的下标检查所涉及的开销比你开始想象的要多。编译器必须在程序中插入指令,证实下标的结果所引用的元素和指针表达式所指向的元素属于同一个数组,可能仅仅是个小功能,生成的程序的数组检查占有大量的代码空间,这必将影响程序的运行效率。

这也让我意识到一个事情:数组的标识符(也就是数组名),它只包含并没有包含数组的长度的信息,它只是个地址信息,也就是上面说的数组名本质上是个常量指针。读到这里,请你想一下,C语言有提供数组长度的底层函数吗???

答案是否定的,一般情况下,我们获取一个数组的长度,我们可以获取数组所占的内存大小,然后除以单个元素的内存大小计算数组长度。

int a[8];
printf("%d",sizeof(a)/sizeof(a[0]));

为什么不修复“漏洞”

既然我们发现了上述问题,那么那些C语言的大神为什么不修复这个“漏洞”呢?其他编程语言会吸取“教训”吗?学过JAVA的同学可以看下面代码:

int [][] array = {{1,2,3},{1,4}};
System.out.println(array[1][2]);

这也是一个数组越界访问的例子,但是JAVA的控制台会打印如下信息:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2

at demo.Array.main(Array.java:31)。

会明确告诉你数组下标越界了,是的,高级语言JAVA是支持的。

那么我们就来讲讲C语言的设计目标:提供一种能以简易的方式编译、处理低级存储器、仅产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

如果C语言加入了类似下标检查,实现一个简单的数组数据写入,需要大量指令检查下标是否正确,那么还符合C语言设计目标吗?如果C语言有大量的这样设计,操作系统内核还会使用C语言编写吗?单片机等实时系统还会使用C语言吗?

所以C语言给了程序员更大空间,C语言执行效率高,可以直接访问硬件,具有非常好的可移植性,所以世界上绝大部分的操作系统内核都是用C语言编写的。

那么问题来了,JAVA都检查了数组下标,C语言难道一点进步也没有吗?其实也不然,微软在这一方面也做了贡献。

在早期的CRT函数中也不对字符串指针或数组进行越界检查,都是要求程序员确保空间足够,因此也才也才有了在VS2005之后微软提供的安全的CRT函数版本。(CRT函数不是本文的重点,不懂的同学请面向百度编程)。

总结

C语言为什么不检查数组下标???答案一个字:快。

责任编辑:姜华 来源: 知晓编程
相关推荐

2022-06-29 09:19:09

静态代码C语言c代码

2022-06-15 11:02:40

网络安全运营

2022-06-27 09:54:38

编程语言JavaC++

2022-04-20 20:28:40

HDF 驱动框架鸿蒙操作系统

2022-06-21 09:26:21

Shell脚本JavaScript

2022-03-16 10:14:55

C语言C++

2022-06-29 08:13:36

漏洞网络攻击网络安全

2022-04-12 11:38:06

C语言全局变量

2022-06-21 14:30:16

Vim自定义Linux

2022-05-10 16:04:40

编程语言PythonC语言

2021-02-24 15:05:32

C语言数组代码

2022-06-17 14:22:02

网络风险管理

2022-04-02 20:27:30

ETS操作系统鸿蒙

2022-06-02 08:03:19

PyCharmPython代码

2014-02-01 21:25:08

Python数组

2022-05-30 10:31:34

Bash脚本Linux

2022-03-08 11:17:54

函数指针回调函数C语言

2022-05-25 10:03:38

机器人智能家居

2022-06-06 06:10:00

密码验证安全

2022-06-13 07:52:43

数据中心数据链路层

同话题下的热门内容

手把手教你用装饰器扩展 Python 计时器IOC-Golang 的 AOP 原理与应用Vue 里,多级菜单要如何设计才显得专业?分析了 700 万份工作需求,市场需求最高的八种编程语言是这些Vue 2.7 正式发布,代号为 Naruto手把手教你实现一个 Python 计时器2022 年编程语言趋势:Swift、Kotlin 热度持续增长,收入最高的五种语言竟是它们分布式事务(Seata) 四大模式详解

编辑推荐

太厉害了,终于有人能把TCP/IP协议讲的明明白白了!牛人5次面试腾讯不成功的经验HBase原理–所有Region切分的细节都在这里了Javascript如何监听页面刷新和关闭事件如何搭建一个HTTPS服务端
我收藏的内容
点赞
收藏

51CTO技术栈公众号