文章目录
未定义行为(Undefined Behavior)
一些编程语言中,某些情况下存在未定义行为,以C和C++最为著名。在这些语言的标准中,规定某些操作的语义是未定义的,典型的例子就是程序错误的情况,比如越界访问数组元素。标准允许语言的具体实现做这样的假设:只要是匹配标准的程序代码,就不会出现任何类似的行为。具体到 C/C++ 中,编译器可以选择性地给出相应的诊断信息,但没有对此的强制要求:针对未定义行为,语言实现作出任何反应都是正确的,类似于数字逻辑中的无关项。
------百度百科
一句话总结: 未定义行为就是运行结果不确定
C和C++的未定义行为的一些例子
尝试修改字符串字面量会产生未定义行为
char * p = "wikipedia"; // C++11中错误,C++98/C++03不推荐使用
p[0] = 'W'; // 未定义行为
防止这一点的方法之一是将它定义为数组而不是指针:
char p[] = "wikipedia"; /* 正确 */
p[0] = 'W';
在C++可以使用[[标准模板库]]中的string类型,如下所示:
std::string s = "wikipedia"; /* 正确 */
s[0] = 'W';
除以零会导致未定义行为
根据IEEE 754,float、double和long double类型的值除以零的结果是无穷大或NaN:
return x/0; // 未定义行为
某些指针操作可能导致未定义行为
int arr[4] = {0, 1, 2, 3};
int* p = arr + 5; // 未定义行为
到达返回数值的函数(除main函数以外)的结尾,而没有一个return语句,会导致未定义行为
int f()
{ } /* 未定义行为 */
《C程序设计语言》在第2.12节引用下面的代码作为未定义行为的例子:
printf("%d %d\n", ++n, power(2, n)); /* 未定义行为 */
以及
a[i] = i++; /* 未定义行为 */
标准库可能指定未定义行为
int x = 1;
printf("%d\n", &x); /*未定义行为:%d预期int类型的实际参数*/
printf("%p\n", &x); /*未定义行为:%p预期void*类型的实际参数*/
printf("%p\n", (void*)&x); /*%p和void*类型的实际参数匹配,不在此引发未定义行为*/
一道例题
下列 C 代码中,不属于未定义行为的有:______。
A :int i=0;i=(i++);
B :char *p=”hello”;p[1]=’E’
C :char *p=”hello”;char ch=*p++
D :int i=0;printf(“%d%d\n”,i++,i–)
E :都是未定义行为
F :都不是未定义行为
正确答案: C
A选项,不知道编译器会怎么选择自增和赋值的顺序,所以这是由编译器决定的,属于未定义行为。
B选项,”hello“这个字符串属于一个字符串常量了,指针p指向了这个字符串常量,通过这个指针来直接修改常量第二个字符,这也属于未定义行为。
C选项,只是通过指针找到第二个字符并将它赋值给一个字符变量,并没有改变这个字符串常量,所以不属于未定义行为。
D选项,在printf语句中,i++和i–谁先执行由编译器决定,这是未定义行为。