不同操作系统中的 compiling/executing 代码是否存在差异?
Is there a difference in compiling/executing code in different Operational Systems?
我刚刚发现了一个问题,但我不知道它可能是什么。我几周前开始学习编程,正在学习指针。
我在两台不同的 PC 上编译了完全相同的代码。首先,程序运行完美。第二种,到达某行时停止工作。
我使用 2 台电脑。
我工作场所的那个运行 Windows XP SP3。在这一个中,程序运行良好。
我家的那个运行 Windows 7 SP1。它编译了代码,但程序没有运行。
我正在两个系统中使用 DEV C++ 和 TDM GCC 5.1.0 编写和编译。
#include<iostream>
using namespace std;
int main (void) {
int* pointer;
cout << "pointer == " << pointer << "\n";
cout << "*pointer == " << *pointer << "\n"; // this is the line where the program stops.
cout << "&pointer == " << &pointer << "\n";
return 0;}
第一台电脑的输出是这样的:
pointer == 0x000001234
*pointer == some garbage value
&pointer == 0x000007865
在第二台电脑上,它停在第二行。
pointer == 0x1
我明白指针还没有分配给变量。因此,它不存储任何正确的地址。即便如此,它至少应该显示其中的垃圾值,或者“0”表示它还没有指向的地址。我知道代码是正确的,因为它在第一台 PC 上运行良好。但是我不明白为什么它在其他电脑上失败了。
I know the code is right because it worked fine in the first PC
你不知道这样的事情。
您有未定义的行为,一个完全有效的结果是一个始终有效的程序。或者除了星期六外总是工作,或者总是工作直到你完成测试并将它运送给付费客户,或者总是在一台机器上工作而在另一台机器上总是失败。
行为是 未定义,而不是 "defined to some specific consistent observable mode of failure"。
具体来说,未定义行为的真正风险不仅仅是某些操作的结果具有未指定的 值,而是它可能具有未定义和不可预测的 side-effects - 在你的程序中明显无关的区域,或者在整个系统上。
Even so, it should at least show the garbage value inside it
确实如此。但是后来你要求它取消引用那个垃圾值。
读取任何一个未指定值的变量本身就是Undefined Behavior,所以UB的第一段是读取指针的值。
跟随(取消引用)未指向有效对象的指针也是未定义的行为,因为您不知道您非法解释为地址的未指定值是否与类型正确对齐,或者是映射到您进程的地址 space.
如果您成功地从该地址加载了一些整数,那是第三种未定义行为,因为它的值也是未指定的。
因此,最坏情况下的直接陷阱(具有硬件陷阱值和限制性对齐)是:
- 读取未指定的指针值,得到陷阱表示,死于硬件陷阱
- 或读取未指定的指针值,将其解释为未对齐的地址,因总线错误而死
- 或者跟随未指定的指针指向未映射的地址,死于段冲突
- 或者在前面的所有步骤中幸存下来 - 纯属偶然 - 从内存中的某个位置加载一些随机值。然后死,因为那个值是陷阱表示。
但是,如果您的进程刚刚死掉,可重复地,您可以轻松地调试和修复它而不会产生不良影响。从这个意义上说,在调用 UB 时崩溃实际上是最好的结果。替代方案更糟糕、更不可预测且更难调试。
I do understand that the pointer have not been assigned to a variable. Therefore, it does not store any correct address. Even so, it should at least show the garbage value inside it, or a "0" to indicate it has not yet an address to point to.
确实如此!那是 0x000001234
.
不幸的是,您随后尝试 取消引用 这个无效指针,并打印不存在的 int
的值。你不能那样做。
如果你没有那样做,我们已经到了第三行,其中 0x000007865
将正确表示指针的地址,它是一个名称为 [=13= 的对象] 并输入确实存在的 int*
。
I know the code is right because it worked fine in the first PC.
您必须习惯使用 C++ 的一件事是 "it appears to work on one computer" 远不能证明代码是正确的。阅读有关 undefined behaviour 的文章,慢慢流泪。
But I do not understand why it failed in other computer.
因为代码不对,你这次没有得到"lucky"。
我们可以分析它似乎在一个系统上运行而不在另一个系统上运行的几个原因,有 个原因。但是已经晚了,你才刚刚起步,因为这是未定义的行为没关系。 :)
我刚刚发现了一个问题,但我不知道它可能是什么。我几周前开始学习编程,正在学习指针。
我在两台不同的 PC 上编译了完全相同的代码。首先,程序运行完美。第二种,到达某行时停止工作。
我使用 2 台电脑。 我工作场所的那个运行 Windows XP SP3。在这一个中,程序运行良好。
我家的那个运行 Windows 7 SP1。它编译了代码,但程序没有运行。
我正在两个系统中使用 DEV C++ 和 TDM GCC 5.1.0 编写和编译。
#include<iostream>
using namespace std;
int main (void) {
int* pointer;
cout << "pointer == " << pointer << "\n";
cout << "*pointer == " << *pointer << "\n"; // this is the line where the program stops.
cout << "&pointer == " << &pointer << "\n";
return 0;}
第一台电脑的输出是这样的:
pointer == 0x000001234
*pointer == some garbage value
&pointer == 0x000007865
在第二台电脑上,它停在第二行。
pointer == 0x1
我明白指针还没有分配给变量。因此,它不存储任何正确的地址。即便如此,它至少应该显示其中的垃圾值,或者“0”表示它还没有指向的地址。我知道代码是正确的,因为它在第一台 PC 上运行良好。但是我不明白为什么它在其他电脑上失败了。
I know the code is right because it worked fine in the first PC
你不知道这样的事情。
您有未定义的行为,一个完全有效的结果是一个始终有效的程序。或者除了星期六外总是工作,或者总是工作直到你完成测试并将它运送给付费客户,或者总是在一台机器上工作而在另一台机器上总是失败。
行为是 未定义,而不是 "defined to some specific consistent observable mode of failure"。
具体来说,未定义行为的真正风险不仅仅是某些操作的结果具有未指定的 值,而是它可能具有未定义和不可预测的 side-effects - 在你的程序中明显无关的区域,或者在整个系统上。
Even so, it should at least show the garbage value inside it
确实如此。但是后来你要求它取消引用那个垃圾值。
读取任何一个未指定值的变量本身就是Undefined Behavior,所以UB的第一段是读取指针的值。
跟随(取消引用)未指向有效对象的指针也是未定义的行为,因为您不知道您非法解释为地址的未指定值是否与类型正确对齐,或者是映射到您进程的地址 space.
如果您成功地从该地址加载了一些整数,那是第三种未定义行为,因为它的值也是未指定的。
因此,最坏情况下的直接陷阱(具有硬件陷阱值和限制性对齐)是:
- 读取未指定的指针值,得到陷阱表示,死于硬件陷阱
- 或读取未指定的指针值,将其解释为未对齐的地址,因总线错误而死
- 或者跟随未指定的指针指向未映射的地址,死于段冲突
- 或者在前面的所有步骤中幸存下来 - 纯属偶然 - 从内存中的某个位置加载一些随机值。然后死,因为那个值是陷阱表示。
但是,如果您的进程刚刚死掉,可重复地,您可以轻松地调试和修复它而不会产生不良影响。从这个意义上说,在调用 UB 时崩溃实际上是最好的结果。替代方案更糟糕、更不可预测且更难调试。
I do understand that the pointer have not been assigned to a variable. Therefore, it does not store any correct address. Even so, it should at least show the garbage value inside it, or a "0" to indicate it has not yet an address to point to.
确实如此!那是 0x000001234
.
不幸的是,您随后尝试 取消引用 这个无效指针,并打印不存在的 int
的值。你不能那样做。
如果你没有那样做,我们已经到了第三行,其中 0x000007865
将正确表示指针的地址,它是一个名称为 [=13= 的对象] 并输入确实存在的 int*
。
I know the code is right because it worked fine in the first PC.
您必须习惯使用 C++ 的一件事是 "it appears to work on one computer" 远不能证明代码是正确的。阅读有关 undefined behaviour 的文章,慢慢流泪。
But I do not understand why it failed in other computer.
因为代码不对,你这次没有得到"lucky"。
我们可以分析它似乎在一个系统上运行而不在另一个系统上运行的几个原因,有 个原因。但是已经晚了,你才刚刚起步,因为这是未定义的行为没关系。 :)