C和C++中的未定义行为

考虑下面的C/C++程序,并尝试猜测输出?

// Program 1 (Divide by 0) 
int main() 
{ 
    int x = 25, y = 0; 
    int z = x / y; 
    printf("Hello World!"); 
    return 0; 
} 
// Program 2 (Uninitialized variables) 
int main() 
{ 
    bool val; 
    if (val) 
        printf("TRUE"); 
    else
        printf("FALSE"); 
} 
// Program 3 (Accessing value of NULL 
// pointer) 
int main() 
{ 
   int *ptr = NULL; 
   printf("%d", *ptr); 
   return 0; 
} 
// Program 4 (Accessing out of bound) 
int main() 
{ 
   int arr[5]; 
  
   // We access arr[5] in last iteration. 
   for (int i=0; i<=5; i++) 
      printf("%d ", arr[i]); 
} 
// Program 5 (Going beyond limit of 
// signed int) 
int main() 
{ 
   int x = INT_MAX; 
   printf("%d", x+1); 
   return 0; 
} 
// Program 6 (Trying to modify a string 
// literal) 
int main() 
{ 
   char *s = "geeksforgeeks"; 
   s[0] = 'e'; 
   return 0; 
} 
// Program 7 (Modifying a variable 
// multiple times before a defined 
// sequence point) 
// https://www.geeksforgeeks.org/sequence-points-in-c-set-1/ 
#include <stdio.h> 
int main() 
{ 
   int i = 8; 
   int p = i++*i++; 
   printf("%d\n", p); 
} 

以上所有程序的输出都是不可预测的(或不确定的)。编译器(实现C/C++标准)可以自由地做任何事情,因为C和C++标准未定义它们。

像Java这样的语言会立即发现错误,但是在少数情况下,像C和C++这样的语言会继续以静默但有错误的方式执行代码,这可能会导致无法预测的结果。该程序可能会因任何类型的错误消息而崩溃,也可能在不知不觉中损坏数据的情况,这是一个严重的问题。

了解未定义行为的重要性

如果用户开始在C/C++环境中学习,并且对不确定行为的概念不清楚,那么将来可能会带来很多问题,例如在调试其他人的代码时,实际上可能很难追踪到未定义错误的根源。

不确定行为的风险和弊端

程序员有时依赖未定义行为的特定实现(或编译器),这可能会在更改/升级编译器时引起问题。例如,最后一个程序在大多数编译器中产生72作为输出,但是基于此假设实现软件不是一个好主意。

未定义的行为也可能导致安全漏洞,特别是由于未检查数组越界的情况(导致缓冲区溢出)。

未定义行为的优点

C和C++具有未定义的行为,因为它允许编译器避免进行大量检查。假设一组具有更高性能数组的代码无需关注边界,这避免了需要复杂的优化过程来检查循环外的此类条件。当紧密绑定循环获得C编译器通常提供的未定义的有符号溢出特性的优点时,会将程序从30%加快到50%的速度。

我们还有另一个优点,因为它允许我们将变量的值存储在处理器寄存器中,并在大于源代码中变量的时间内进行操作。它还有助于进行环绕式检查,然后进行编译时检查,而如果没有更多的C/C++编译器未定义行为的知识,这将是不可能的。

六一编程网

发表评论

电子邮件地址不会被公开。 必填项已用*标注

Next Post

在Python中接受输入

周三 3月 25 , 2020
开发人员通常需要与用户进行交互,以获取数据或提供某种结果。今天,大多数程序都使用对话框来要求用户提供 […]