C语言的未定义行为(undefined behaviour)
什么是未定义行为
简单地说,未定义行为是指C语言标准未做规定的行为。编译器可能不会报错,但是这些行为编译器会自行处理,所以不同的编译器会出现不同的结果,什么都有可能发生,这是一个极大的隐患,所以我们应该尽量避免这种情况的发生。
特征
包含多个不确定的副作用的代码的行为总是被认为未定义。(简单而言, “多
个不确定副作用” 是指在同一个表达式中使用导致同一对象修改两次或修改以后
又被引用的自增, 自减和赋值操作符的任何组合。这是一个粗略的定义)
例子
在网上了解了一番,发现未定义行为有很多,而我初出茅庐,遇到的情况不多,只有借鉴前人的经验。总结了一些前人遇到的问题。下面三种未定义行为是前人总结的,我只是加上了一点自己的理解。有错误望指出。
附原文地址:http://www.itoldme.net/archives/904
第一例(同一个表达式中有多种运算符)
在同一个表达式中多种运算符一起计算的时候,即使我们知道各符号都有自己的优先级或者是人为的加上括号限制计算顺序,但是我们却不知道编译器会先计算哪一段,计算顺序完全取决于编译器,所以结果并不一定按照我们预想中的输出。
代码段一
int i=7;
printf(“%d”, i++*i++);
编译器可以选择使用变量的旧值相乘以后再对二者进行自增运算。没有任何保证确保自增或自减会在输出变量原值之后和对表达式的其它部分进行计算之前立即进行。
代码段二
int a=5,b;
b=++a*–a;
b的值不能确定
代码段三
int i = 5;int j = (++i) + (++i) + (++i);
j的值不能确定
代码段四
#include <stdio.h>int main(){int i = 0;int a[] = {10,20,30};int r = 1 * a[i++] + 2 * a[i++] + 3 * a[i++];printf("%d\n", r);return 0;
}
这段代码也并不是我们想象中的那样按照优先级来计算,编译器选择了他自己的一种套路,
此段代码详细实现情况请戳链接:http://blog.jobbole.com/53211/
第二例(同一语句中各参数的求值顺序)
在同一语句中,有多个表达式,我们不能确定编译器先调用哪一个表达式进行运算,运算之后又会对另一个表达式产生影响,因为他不一定是按照我们想象中自左向右进行调用的。
代码段一
printf("%d,%d\n",++n,power(2,n));
代码段二
int f(int a, int b);
int i = 5;
f(++i, ++i);
第三例(通过指针修改const常量的值)
编译器对于向常量所在内存赋值这件事的处理是未定义的。即在对常量的内存操作也许并不是我们想象的那样。
代码段一
int main()
{const int a = 1;int *b = (int*)&a;*b = 21;printf("%d, %d", a, *b);return 0;
}
该段代码的详细实现请戳链接:http://www.cnblogs.com/wghost/p/3280074.html
总结
个人认为,未定义行为实在难以确切的分类出来,幽默一点的说就是,水实在很深,所以我只是简单了解一下,更多的情况也只有日后再编程过程中慢慢积累。前辈的文章也着实很详细,看了之后基本上就会有一个大致的了解了。
练习题
解析:根据上面的总结,A选项,我的理解是我们不知道编译器会怎么选择自增和赋值的顺序,所以这是由编译器决定的,属于未定义行为。B选项,”hello“这个字符串属于一个字符串常量了,指针p指向了这个字符串常量,下一语句通过这个指针来直接修改常量第二个字符,这也属于未定义行为。选项C,只是通过指针找到第二个字符并将它赋值给一个字符变量,并没有改变这个字符串常量,所以不属于未定义行为。选项D,在printf语句中,i++和i–谁先执行由编译器决定,这是未定义行为。故此题选C。
C语言的未定义行为(undefined behaviour)相关推荐
- C语言中出现UB现象 undefined behaviour.
- c语言ok未定义标识符,C语言中宏的相关知识 - osc_y7ckpzr9的个人空间 - OSCHINA - 中文开源技术交流社区...
2019/04/27 16:02 1.宏的定义:宏定义就是预处理命令的一种,它允许用一个标识符来表示一个字符串.格式如下: #define name(宏名) stuff(字符串) 本质就是使用宏名去替 ...
- c语言 linker error,[Linker error] undefined reference to `prinf'的问题!
[Linker error] undefined reference to `prinf'的问题! 环境为dev-cpp 日志如下: 编译器: Default compiler 执行 gcc.exe. ...
- c语言函数未定义的引用,c – CMake“未定义的函数引用”
我试图使用CMake链接库( BNO055 Driver).由于BNO055驱动程序不使用CMake并且大约一年没有更改,我决定只下载源文件并将它们放入我的项目中. 然后我使用CMake创建一个库并链 ...
- c语言中未定义标识符,未定义标识符
源自:4-5 C++新特性以及输入输出演示 未定义标识符 代码: #include "iostream" #include "stdlib.h" #includ ...
- C语言函数未定义警告的解决方法
问题:在C语言中,自定义函数并进行调用,运行后提示"函数未定义"的警告 修改前代码段: #define _CRT_SECURE_NO_WARNINGS 1 #include < ...
- c语言ofstream未定义标识符,关于c++:c中ifstream及ofstream超详细说明
前文说过,ifstream是继承于istream,ofstream是继承于ostream,fstream是继承于iostream类,而他们应用的缓冲区类是filebuf. 对于这些类之间的关系,有趣味 ...
- C++未定义行为-数组越界
我们先来看看下面的代码: #include <iostream> using namespace std; const int N = 100010; int a[N]; int main ...
- c语言中未定义标识符IDD,一、Windows对话框—对话框及其模板
要把一个对话框添加到Visual C++ Developer Studio会有的应用程序上,可以先从Insert菜单中选择Resource,然后选择Dialog Box.现在一个对话框出现在您的眼前, ...
最新文章
- 【aelf开发者社区招募】重构 C#代码--中高级工程师预期小半天到一天
- CFCC百套计划2 CodeChef December Challenge 2017 Chef And Easy Xor Queries
- MAC OS中的dylib 的@rpath和@loader_path小问题
- JAVA中常用的逻辑运算符_Java中常用的运算符
- string转成对象_详解Java I/O流(五),对象序列化
- phpcms文件结构
- java 电子编号生成器_业务编号生成器
- Django使用消息提示简单的弹出个对话框
- 基于vue的video播放组件
- tcp状态转换--三次握手/四次挥手
- tomcat 报错:Error occurred during initialization of VM
- linux vnc 安装目录,Linux环境VNC服务安装、配置与使用(图)
- Qt Qt5.15+Xcode12+BigSur macOS及iOS开发环境搭建
- 蒲公英联机平台的服务器虚拟IP,蒲公英客户端如何使用固定虚拟IP管理虚拟局域网的步骤是什么?...
- 网易云音乐 linux x32,网易云音乐UWP版旧版本安装包 拒绝更新Win32转制版
- xgene:肿瘤相关基因 EGFR,,Her2,,TP53,,ALK
- 云端服务器怎么修改密码,云端服务器怎么设置登录密码
- 有甲乙丙丁四个字,取出任意三个字,打印所有可能性
- 路在脚下,却不知怎么去走?
- 163手机登录邮箱显示服务器无法登录,163邮箱登陆不了_为何无法正常登录邮箱 ?...