C 为什么编译器分配的内存比需要的多?

C 为什么编译器分配的内存比需要的多?,c,C,我进行了一些调试,发现编译器分配的内存比所需的多。在我的例子中,我声明了一个整数,后跟一个字符串“name[10]”。尽管我刚刚提到了10个字母,但我能够插入10多个字母。我也能打印所有这些字符。我注意到限制不是10,而是28。未显示在28之后插入的字符。有人能解释一下为什么会这样吗?大多数系统(CPU体系结构/操作系统/编译器组合)以不小于单个页面的分辨率(通常至少为4KB)为进程分配内存。如果您分配的10个字节在一个页面的开头结束,那么您可以在不导致页面错误的情况下(根据填充、元数据等的不同

我进行了一些调试,发现编译器分配的内存比所需的多。在我的例子中,我声明了一个整数,后跟一个字符串“name[10]”。尽管我刚刚提到了10个字母,但我能够插入10多个字母。我也能打印所有这些字符。我注意到限制不是10,而是28。未显示在28之后插入的字符。有人能解释一下为什么会这样吗?

大多数系统(CPU体系结构/操作系统/编译器组合)以不小于单个页面的分辨率(通常至少为4KB)为进程分配内存。如果您分配的10个字节在一个页面的开头结束,那么您可以在不导致页面错误的情况下(根据填充、元数据等的不同稍微增加或减少)读取和写入超过该页面结尾的4086个字节。

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

在你不应该写的地方写作会引发未定义的行为,这意味着它可能有效,也可能无效,也可能没有后果


这些后果之一就是所谓的as,一种允许运行任意代码的安全漏洞,被蠕虫和漏洞广泛用于入侵计算机系统。

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


C假设您知道阵列有多大,并且您足够聪明,不会在阵列之外徘徊

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