c - 指向内存负地址的 C 编译器行为是什么?
问题描述
在 C 代码段下面编译运行后 p1、p2 的状态是什么?
char *p1 = malloc(5);
char *p2 = p1 - 3;
*p2 = '\0';
解决方案
如果您要将此 C 代码直接转换为简单机器上的简单机器代码,char *p2 = p1 - 3;
则将设置p2
为指向内存中比 更早的三个字节p1
,并将*p2 = '\0'
零写入不正确的位置。我们不知道那个位置是什么,所以我们不能说效果是什么。
但是,现代编译器通常不会将 C 代码直接转换为简单的机器代码。他们解释 C 代码并对其进行复杂的优化。因此,了解发生了什么需要使用 C 标准或正在使用的编译器的文档。
关于这段代码,C 标准告诉我们什么?对于p1 - 3
,适用于 C 2018 6.5.6 8 中的指针加法规则:
当一个整数类型的表达式被添加到一个指针或从一个指针中减去时,...... 如果指针操作数和结果都指向同一个数组对象的元素,或者超过数组对象的最后一个元素,则评估不应产生溢出;否则,行为未定义。
因为p1
指向由 提供的对象(可以用作数组)的元素malloc
,p1 - 3
而不指向该数组的元素,所以 C 标准没有定义行为。因此,如果我们以C标准作为理解的基础,一旦p1 - 3
被评估,我们就不能说程序的行为或状态p1
是什么p2
。
推荐阅读
- javascript - 在ajax之后加载元素后选择一个DOM元素
- python-3.x - 删除列时的轴
- oracle - Oracle XML 表解析不获取没有子节点的节点
- javascript - css删除logo周围的虚线
- ios - Firebase 数据库不适用于 Facebook Expo 身份验证
- docker - 在 docker swarm 版本 17.03 上使用主机网络
- php - 即使安装了 zip 扩展,也找不到类“ZipArchive”
- http - 支持简单 HTTP 和 Websocket 的服务器上的用户身份验证
- javascript - 为什么让作用域说变量未在嵌套作用域中定义?
- java - 从 MS 获取 JDBC 驱动程序到 Eclipse