【问题标题】:Same source code but different result on different operating systems相同的源代码,但在不同操作系统上的结果不同
【发布时间】:2015-12-22 05:35:18
【问题描述】:

我正在学习指针。我在教程中看到了这个代码示例。我试过了,但它给出了与教程不同的结果。

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i = 5;
    int myInt = 7;
    int *pointer = &i;
    printf("%i\n", *(pointer + 1));

    return 0;

}
  • 在 windows 机器上,输出为 2686740

  • 在 linux 机器上,输出为 7。

这是什么原因?

【问题讨论】:

  • 查找undefined behavior。在*(pointer + 1) 上没有什么特别保证存在,因为代码从不为其分配或保留任何东西。另外,请指出“教程”,以便其他人知道避免它。
  • @dxiv 我不知道这是否是一个糟糕的教程。事实上,我是一个绝对的初学者。 [链接]youtu.be/5jQ2ZiXzJjE?t=3m57s
  • 仅从您发布的示例来看(抱歉,没有也不会观看视频),这要么是一个糟糕的教程,要么是针对不同受众的关于编译器/操作系统的一些特殊情况的教程行为。在任何一种情况下,learning pointers 的来源都是完全错误的。给自己找一些其他基本的、成熟的、有信誉的书籍或在线教程。一旦您了解为什么您刚刚发布的问题在标准 C 的上下文中没有意义,请在此处添加您的答案,我将是第一个支持它的人。
  • @HakanAs 这是一个垃圾教程,别看了。作者在评论中说:“编译器不保证变量会这样排列。我只是假设因为它们是给我的,所以它们是给大多数人看的,但我想我错了。 "所以他对 C 基础知识一无所知,但他认为创建一个 C 教程系列是个好主意...

标签: c pointers dereference pointer-arithmetic


【解决方案1】:

为了详细说明现有的答案,我想添加一个解释。

在您的代码中,i 是一个 int 变量。您将i 的地址分配给pointer。美好的。然后,你要做的就是增加指针(地址),然后尝试取消引用它。

现在,与代码中的语句相比,

printf("%i\n", *(pointer + 1));    

引用C11 标准,第 §6.5.6 章,加法运算符

[....] 如果两个指针 操作数和结果指向同一数组对象的元素,或最后一个元素 数组对象的元素,评估不应产生溢出;否则, 行为未定义。 如果结果指向数组对象的最后一个元素,它 不得用作被评估的一元 * 运算符的操作数。

实际上,通过这样做,您正在尝试访问一些未分配给您的进程的内存,从而调用undefined behavior

UB 的输出,嗯,undefined

【讨论】:

  • 感谢您的解释和分享我以前不知道的参考资料。
【解决方案2】:

内存(这里是栈)是这样的

[ i ][ something else .... 
^    ^
^    pointer+1 
pointer

在做

int *pointer = &i;
printf("%i\n", *(pointer + 1));

您显示一个int,即sizeof(int)pointer+1 的内存空间被读取为int,这是编译器没想到您会这样做的,并且该空间是“未知的”。所以 Windows 可能会显示 X,Linux 也可能会这样做,显示其他内容甚至崩溃......

这是未定义的行为。

【讨论】:

    【解决方案3】:

    您正在对未分配给该指针/引用的区域进行指针运算,因此它是未定义的。它可以按照编译器的意愿实现。

    真正的原因是在linux上,变量my int位于地址&i + 1,而在windows上……它在别的地方

    【讨论】:

      【解决方案4】:

      我认为代码正在对可能存在或不存在的内存布局做出假设。假设是:堆栈是线性的,变量完全按照源中声明的方式存储。这在某种程度上意味着您假设编译器不会进行任何优化。

      在 Windows 上尝试以下操作:(i) 关闭编译器的所有优化,(ii) 或在调试模式下运行。该行为可能会或可能不会切换到 Windows 上的“预期”行为。教训是:不要写这样的代码;)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-05
        • 1970-01-01
        相关资源
        最近更新 更多