为啥编译器分配的内存比需要的多? [复制]

Posted

技术标签:

【中文标题】为啥编译器分配的内存比需要的多? [复制]【英文标题】:Why does the compiler allocate more memory than required? [duplicate]为什么编译器分配的内存比需要的多? [复制] 【发布时间】:2014-07-24 03:40:52 【问题描述】:

我进行了一些调试,发现编译器分配的内存超过了所需的内存。在我的例子中,我声明了一个整数,后跟一个字符串'name [10]'。即使我刚刚提到了 10 个,我也能够插入 10 个以上的字母。我还能够打印所有这些字符。而且我注意到限制不是10而是28。在28之后插入的字符没有显示出来。有人可以向我解释为什么会这样吗?

【问题讨论】:

您正在调用未定义的行为——这很糟糕。编译器分配填充空间以确保数据(整数)在内存中正确对齐(可能在一个 4 字节的倍数的地址上),以便高效地访问它。很有可能,如果你写了超过 11 个字符加上终端 null,那么你是在结构之外写的。那很糟!这是缓冲区溢出的来源(即使在分配的 10 个字节之外写入也是缓冲区溢出),并且要不惜一切代价避免。 C 不是保姆语言。它可以让你在脚下射击自己。尽量不要跛行。 “我注意到限制不是 10 而是 28”你是如何进行这个测量的? 仅仅因为您可以写入未分配给您的内存并不意味着编译器正在做一些意想不到的事情。当您未能履行与编译器/库/运行时/等协商的合同时,系统可能会或可能不会决定对此做些什么,但没有任何形式的保证...... @DDR 如果您需要更具体的解释,请显示您正在使用的实际代码。 @AndrewMedico:对齐填充不能出现在结构的开头;它发生在元素之间或结构的末端。如果结构是struct int i; char s[10]; ;,那么结构之后通常会有 2 个字节的填充。通常不会有 28 个字节作为结构的一部分。但正如我所指出的,C 语言并不会阻止你越界编写变量——当你在编写越界时遇到麻烦取决于很多因素。通过越界写入来调用未定义的行为意味着任何事情都可能发生(包括“它几乎可以工作”!) 【参考方案1】:

它并没有为该变量分配更多内存,您只是碰巧能够写入它旁边的某些内存部分,但是这样做您可能会覆盖其他变量,甚至是您无法控制的变量,例如调用堆栈或内存管理器自身创建的控制变量。

在你不应该写的地方会引发未定义的行为,这意味着它可能会或可能不会起作用,并且可能会或可能不会产生后果。

其中一个后果被称为stack buffer overflow,这是一个允许运行任意代码的安全漏洞,并被蠕虫和漏洞利用程序广泛用于入侵计算机系统。

【讨论】:

【参考方案2】:

C 不对数组访问进行边界检查,因此当您访问数组边界之外的内容时,它不会自动引发异常。如果你不破坏任何“重要”的东西(例如返回地址),你的代码不会立即崩溃,并且可能看起来可以正常运行。

C 假设您知道数组有多大,并且您足够聪明,不会在它们之外徘徊。

【讨论】:

【参考方案3】:

大多数系统(CPU 架构/操作系统/编译器组合)以不小于单个页面的分辨率为进程分配内存,通常至少为 4KB。如果您分配的 10 个字节最终在页面的开头,您可能能够在页面末尾读取和写入最多 4,086 个字节而不会导致页面错误(取决于填充、元数据等) .

【讨论】:

以上是关于为啥编译器分配的内存比需要的多? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的编译器在 c++ 中使用动态分配的内存时给我错误

编译器如何在 struct 中完成内存分配? [复制]

当试图释放堆管理器分配的内存时会发生啥,它分配的比要求的多?

为啥mac不需要包含智能指针? [复制]

Malloc使用的内存比指定的多?[重复]

计算机内存为啥要有堆栈区?