5

当我在 Windows 和 Linux 上运行下面编写的代码时,我会得到两者不同的输出。

我对两者都使用 gcc。当我在 Windows 上运行它时,我得到“Seek”作为输出,而在 Linux 上运行它时,我得到“Hide”作为输出。Windows 和 Linux 的内存布局有什么不同,还是有其他原因导致输出不同?

int main()
{
    int a=0;
    int *b=(int *)malloc(sizeof(int));
    if(&a>b)
        printf("Hide");
    else
        printf("Seek");
    return 0;
}
4

3 回答 3

9

是的,windows 和 linux 的内存布局不同。这里有一些例子。例如,windows 通常在内核和用户空间之间平均分配内存(以 32 位为单位),而 linux 是 3/1 用户/内核。

编译器还可以在规范的限制内按其认为合适的方式布置内存。这意味着 llvm 编译器、gcc 以及它们的不同版本可以有不同的输出。

优化还可以改变布局,甚至删除一些不是严格需要的变量。

此外,即使内存从低到高分配,在其他一些内存被释放后,新的分配可能来自先前使用的区域并再次变低。

简短的回答:期望不相关变量之间的内存布局/位置不是一个好主意。

于 2012-07-27T12:20:05.943 回答
0

的返回值malloc未指定(可以是任何值)。换句话说,标准的任何部分都不能保证返回值的可预测性。这是 C 语言标准的一部分,而不是特定于平台的,并且与内存布局没有真正的关系。来自 C99 标准:

7.20.3 内存管理功能

1 连续调用 calloc、malloc 和 realloc 函数分配的存储顺序和连续性未指定. 如果分配成功,则返回的指针经过适当对齐,以便可以将其分配给指向任何类型对象的指针,然后用于访问已分配空间中的此类对象或此类对象的数组(直到空间被显式释放) . 已分配对象的生命周期从分配一直延伸到解除分配。每个这样的分配都应产生一个指向与任何其他对象不相交的对象的指针。返回的指针指向分配空间的开始(最低字节地址)。如果无法分配空间,则返回空指针。如果请求的空间大小为零,则行为由实现定义:要么返回空指针,要么行为就像大小是某个非零值一样,

您遇到的是实现定义的行为,不能保证将来会保持这种行为。事实上,它甚至不能保证在当前版本的 Windows/Linux 中保持不变。

于 2012-07-27T12:14:05.493 回答
0

在 Linux 上,您经常有地址空间布局随机化(这也可能发生在 Windows 上)。因此,比较可能会从一次运行到另一次运行给出不同的结果(特别是如果您的代码位于某个共享库中,该库会随机mmap生成)。

为了理解内存映射,您可以/proc/self/maps通过添加以下 Linux 特定代码来显示:

{
   char linbuf[128];
   FILE* mapfil=("/proc/self/maps");
   if (!mapfil) 
     perror("/proc/self/maps"), exit(1);
   while (!feof (mapfil)) {
     memset(linbuf, sizeof(linbuf), 0);
     fgets(linbuf, sizeof(linbuf), mapfil);
     fputs(linbuf, stdout);
   };
   fclose(mapfil), fflush(NULL);
}

(将该代码放在您的 之后,并在没有它的每个格式字符串中malloc添加一个)。\nprintf

pmap如果您有程序的进程 ID,也可以使用该实用程序。

于 2012-07-27T14:12:12.023 回答