我已经学习了两个月的C ++,现在我正在研究我的书(使用C ++编程原理和实践)中有关错误的章节。但在研究了第一页后,我有一个问题:运行时错误和逻辑错误之间的区别是什么?根据我的书,运行时错误是运行时检查发现的错误,我们可以进一步将运行时错误分类为:
虽然逻辑错误只是程序员找到错误结果的原因所发现的错误。
我以为自己已经理解了这种差异,但是作者提供的一个例子让我产生了怀疑。这是一个例子:
#include "std_lib_facilities.h"
int area(int lenght, int width) // calculate area of rectangle
{
return lenght * width;
}
int framed_area(int x, int y) // calculate area within frame
{
return area(x - 2, y - 2);
}
int main()
{
int x = -1;
int y = 2;
int z = 4;
int area1 = area(x, y);
int area2 = framed_area(1, z);
int area3 = framed_area(y, z);
double ratio = double(area1) / area3;
}
以下是作者简要介绍此示例的内容:
函数area()和framed_area()的调用导致否定 值,表示区域,分配给area1和area2。应该 我们接受这样的错误结果?但在回答这些问题之前 在计算比率面积时,看一下比率的计算3 将为0,0除法将导致硬件检测到错误 用一些神秘的消息终止程序。这是 如果您,您或您的用户必须处理的错误 不要对运行时错误进行合理的检测和处理。
这里我不明白为什么用作计算区域的函数的参数的负值被视为运行时错误,这不仅仅是逻辑错误吗?我认为运行时错误只是错误,例如将数字除以0和其他特殊情况。我错了还是我只是误解了什么? 逻辑错误和运行时错误之间的真正区别是什么?您能告诉我一些小例子吗?
答案 0 :(得分:3)
运行时错误可能合法地发生:例如某些文件包含垃圾数据,或者某些错误的人工输入,或者某些资源不足(没有更多内存,磁盘空间已满,硬件损坏,网络连接失败)。
逻辑错误(或失败的assert
....)根据定义总是程序中某些错误的症状,例如:用于二分法访问的所谓排序数组,恰好是未排序的。
请参阅documentation of <stdexcept>
标题:
std::logic_error:此类定义作为异常引发的对象类型,以报告程序内部逻辑中的错误,例如违反逻辑前置条件或类不变量。
std::runtime_error:此类定义作为异常引发的对象类型,以报告只能在运行时检测到的错误。
我相信std::logic_error
的内部逻辑是一个错字,我理解为内部逻辑(程序的),但我是不是以英语为母语的人。
如果您正式确定了程序的规范(例如,在Frama C的帮助下使用ACSL),您可能会发现(也许是正确的)逻辑错误;但你应该关心运行时错误。但你也可能在规范中有bug。
了解Ariane 5 flight 501 failure。并查看J.Pitrat's blog以获得其他观点。
答案 1 :(得分:1)
你的书在第一个分部,编译时与运行时完全正确 如果可以,请确保您获得前者而不是后者,因为它会被自动检测到。
两者都可以进一步细分也是对的,但让我们只看后者:
外部错误:硬件错误/操作系统错误
其中许多是预期的,例如网络不可靠,缺少用户文件等。通常,人们可以从中恢复。
其他是意外的,并且通常是不可恢复的,例如缺少必需的依赖性,不可靠的RAM,耗尽时钟等。期待简单地崩溃和燃烧。
输入错误:乱码输入数据,丢失输入数据等等。
这应该由您的应用程序检测到,根据错误的严重程度,可能会替换默认值,尝试恢复它或只是崩溃和烧毁。
逻辑错误:该程序的基本假设已被发现。
没有什么可以依靠持有更长时间,唯一明智的选择是立即崩溃和燃烧以试图控制损害。
常见的逻辑错误是fencepost-errors(off-by-one),竞争条件,free-after-free等。
请注意std::logic_error
,尽管它的名字,但并不总是表示程序逻辑中的致命故障,因此可能是预期的并且相对温和。
答案 2 :(得分:0)
逻辑错误是由于程序员思维方面的缺陷造成的,并且是可以预防的。例如,忘记防止数组中的越界错误。
另一方面,运行时错误来自计算机体系结构和操作系统,并且超出了程序员的控制范围,在编码过程中无法轻易预测。答案 3 :(得分:0)
关于您提供的示例,为方法计算区域提供负输入是一个逻辑错误,因为您已经(作为应用程序的开发人员)知道这是错误的。但是假设你编写了计算区域的方法,并且你把它给了一个不知道计算区域是什么的用户 - 他可能会提供不正确的输入,这会导致错误的结果。在这种情况下,它将是一个运行时错误,因为用户不知道并且没有错误检查。
答案 4 :(得分:0)
#include <iostream>
using std::cout;
using namespace std;
int area(int lenght, int width) // calculate area of rectangle
{
return lenght * width;
}
int framed_area(int x, int y) // calculate area within frame
{
return area(x - 2, y - 2);
}
int main()
{
int x = -1;
int y = 2;
int z = 4;
int area1 = area(x, y);
int area2 = framed_area(1, z);
int area3 = framed_area(y, z);
double ratio = double(area1) / area3;
cout<<area1<<endl
<<area2<<endl
<<area3<<endl
<<ratio<<endl;
system("pause");
return 0;
}
如何尝试这个没有运行时错误,我不知道如何在没有cout的情况下看到输出结果。
我也是一个新的学习者,我认为在学习的短时间内练习是很重要的。
这只是我的建议,因为上面的两个答案已经得到了很好的解释。
答案 5 :(得分:0)
根据我对自己的经验:) ...
当我们应该为自己构建一个异常逻辑时,混淆可能源于我们“简化生活”。 std例外是我们的代码捕获(未抛出)。它们告诉我们从std库调用函数时发生了什么,并且异常继承树的逻辑不能简单地在库外转移。
std::runtime_error
告诉我们嗯!不可预测的事情发生了
std::logic_error
告诉我们哦!您在代码中省略了一些重要内容
你的老板可以写一个像
这样的程序try { mainCall(); }
catch (const std::logic_error &) { std::cout << "No premiums this year!"; }
catch(const std::runtime_error &) { std::cout << "I know it’s not your fault..."; }
现在,当我们想在代码中重用这个逻辑时,问题就出现了。使用std::string
构造函数和.what()
方法的例外情况已经准备就绪,那么为什么要重新发明轮子呢?
现在困境来了:
double a,b;
std::cin >> a;
std::cin >> b;
if (b == 0) EXCEPTION;
else std::cout << a/b;
那么EXCEPTION
是什么样的?是runtime_error
还是logic_error
?
runtime_error
。logic_error
。我们直观地倾向于将runtime_errors
分配给硬件错误,将logic_errors
分配给“逻辑”错误 - 因此在上面的示例中会选择logic_error
。但是直觉通常是编程的一个不好的指导......只需将你的代码提供给老板的测试单元;)
从std :: exception(或其他)开始派生自己的异常树,或者不尝试解决runtime / logic_error困境。 它没有std库域之外的解决方案......
答案 6 :(得分:0)
当您的计算机系统(操作系统和/或固件)必须处理意外的指令时,发生运行时错误。在大多数情况下,发生运行时错误时,程序会崩溃。例如,内存泄漏是从未释放的新内存的分配。但是,当您的程序中发生无法预料的行为时,很容易识别出逻辑错误。假设您希望程序将两个数字相加,但会将它们相乘。这是一种逻辑错误,只需使用正确的运算符就可以解决。
希望这会有所帮助