a[i] = i++ 到底对不对?
编程中有时会遇到一些有歧义的表达式,比如 a[i] = i++ 。那么 a[i] = i++ 到底对不对呢?
首先请看如下代码:
#include<stdio.h>
int main(){
int i=0;
int a[3] = {1,2,3};
a[i] = i++;
printf("%d n",a[i]);
printf("%d %d %d ",a[0],a[1],a[2]);
return 0;
}
对于这个表达式中 a[i] = i++,子表达式i++有一个副作用,它会改变i的值,由于i在同一表达式中会被引用,因此这样会导致未定义的行为。因为无法判定该引用(该公式中的左边的a[i]中)是新值还是旧值。
不同的编译器在解释此类行为的时候会有不同的理解,比如下面三个编译器(dev c++ 、 codeblocks、vs2019 )对于上述的代码就有不同的理解。
从上面的运行的截图可以观察到相同的一段代码,dev c++和codeblocks的执行结果是相同的,但是vs2019和它们却并不相同。
对于此类行为,尽管有些文献中认为这类表达式的行为是不确定的,但是c标准却强烈声明它是未定义的。
未定义行为的其他示例包括访问超出其边界的数组, 解除引用空指针, 在生命终结后访问对象 或写作 据称聪明的表达 喜欢 i++ + ++i
。
未定义的行为还有两个不那么危险的兄弟, 不确定的行为 和 实现定义的行为。
那么实现定义的行为、不确定的行为、未定义的行为这三者的区别在哪里呢?
首先这三种情况都代表了c语言标准中没有明确要求某个特定构造或使用它的程序必须完成的事情的领域。c语言定义中的这种松散性是传统的,但是这种规定方式是经过深思熟虑的,这种定义方式允许作者:
1 选择某些构造可以按照“硬件完成的方式”生成高效的代码。
2 忽略某些太难准确定义、并且可能在良好书写的程序中没什么实际用处的边界构造。
对于这3种“标准中没有准确定义的行为“的定义如下:
1 实现定义的行为
抽象机的某些方面和操作在本国际标准中描述为 实现定义 (例如, sizeof(int)
)。这些构成了抽象机器的参数。每个实施应包括描述其在这些方面的特征和行为的文件。
2 不确定的行为
抽象机的某些其他方面和操作在本国际标准中描述为 不明 (例如,评估函数参数的顺序)。在可能的情况下,C语言国际标准定义了一组允许的行为。这些定义了抽象机器的非确定性方面。
3 未定义的行为
任何事情都有可能发生,标准对此没有任何要求,程序可能编译失败、运行错误(直接崩溃或者生成错误的结果)或者幸运的如程序员所愿。
既然标准对编译器没有进行任何要求,那么编译器就可以做出任何可能的行为。在程序中忍受未定义的想法是极其危险的,未定义行为比你想象的还要未定义。
如果大家想书写可移植代码,那么上述的三种行为都是需要极力避免的。因此我们在编写代码时最好避免 a[i] = i++ 这种C语言未定义的写法。
- 备份重于一切:远离“Gitlab删库事件”,QBackup是你的最佳选择!
- FFMPEG指令
- Gitlab删库事件回顾,备份手段还停留在“原始社会”?
- ASM 翻译系列第三十二弹:自制数据抽取小工具
- WordPress集成SendCloud邮件代发,规避SMTP泄漏网站主机真实IP的风险
- ASM 翻译系列第三十三弹:REQUIRED_MIRROR_FREE_MB的含义
- 放弃Python转向Go语言:这9大理由就够了 !(附代码)
- CCKiller:Linux轻量级CC攻击防御工具,秒级检查、自动拉黑和释放
- 利用HSTS安全协议柔性解决全站HTTPS的兼容性问题
- Nginx内容替换模块http_substitutions_filter_module及实用案例分享
- libmemcached编译安装报错解决记录
- 解决网站静态缓存后WP-PostViews插件不计数的问题
- Haproxy安装部署文档及多配置文件管理方案
- ASM 翻译系列第三十四弹:ASM磁盘组重要属性介绍
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- MySQL limit导致的执行计划差异
- 3分钟短文:用Laravel的方式管理服务器的文件们
- 漫画:什么是 “抽象工厂模式” ?
- 啥?Grafana 还能为日志添加告警?
- Docker映射详解,没问题了!
- 写了很久!详细理解Spring和IoC
- 一位摸金校尉决定转行前端
- CentOS7下搭建并体验HFish开源蜜罐系统
- 唐朝人更懂React
- 唐朝人更懂React
- 一起学习PHP的runkit扩展如何使用
- CentOS7下部署开源网络流量回溯分析系统Moloch
- spring源码(八)
- 通过源码理解rarp协议(基于linux1.2.13)
- 详解Im2Col+Pack+Sgemm策略更好的优化卷积运算