C++/C 程序未定义行为 实例
除零
int main()
{
int x = 25, y = 0;
int z = x / y;
printf("Hello World!");
return 0;
}
变量未初始化
int main()
{
bool val;
if (val)
printf("TRUE");
else
printf("FALSE");
}
访问空指针NULL
int main()
{
int *ptr = NULL;
printf("%d", *ptr);
return 0;
}
访问越界
int main()
{
int arr[5];
// We access arr[5] in last iteration.
for (int i=0; i<=5; i++)
printf("%d ", arr[i]);
}
有符号int的溢出
int main()
{
int x = INT_MAX;
printf("%d", x+1);
return 0;
}
试图更改字符串字面值
int main()
{
char *s = "geeksforgeeks";
s[0] = 'e';
return 0;
}
在一个序列操作值未确定的情况下对一个变量多次更改
#include <stdio.h>
int main()
{
int i = 8;
int p = i++*i++;
printf("%d\n", p);
}
以上这些程序的输出都是不可预测的,也就是未定义的。C/C++标准编译器对这些文定义的行为可以做任何事情。像java这样的语言往往会在发现问题时立即解决,凡是对于C/C++在某些情况下可能会继续执行程序即便代码存在错误,因此会导致不可预测的结果。程序可能会以任意类型的错误而崩溃crash。
了解未定义行为的重要性
不了解C/C++的UB行为,可能会因此给后续使用者带来大量的问题,而难以debug发现。
未定义行为的风险和缺点
程序员有的时候会依赖于某个特定的编译器对undefined behaviour的实现,但是这样是很不好的!因为当编译器升级或者更换编译器后都会带来新的问题。另一方面,UB也会带来程序的安全缺陷,比如数组访问的越界问题,可能会导致缓冲区溢出攻击。
未定义行为存在的优点
因为UB的存在,编译器不需要做过多的范围检查,以此可以带来极大效率提升。除此之外还有一些其他的优点。