这对于所述架构和操作系统来说是正确的。 (C 标准允许char
to be more超过8位长,但现在这种情况很少见;我知道的唯一例子是TMS320 https://en.wikipedia.org/wiki/Texas_Instruments_TMS320DSP 系列,其中char
可能是16位。不允许更小。)
注意sizeof(char) == 1
根据定义因此通常被认为是不好的写作风格sizeof(char)
or foo * sizeof(char)
在你的代码中。
...我希望两个缓冲区的大小均为 1 字节/8 位。
这也是正确的(但见下文)。
- 一个 ASCII 字符有 7 位长,我希望每个缓冲区能容纳两个字符。
This is not correct, for two reasons. First, nobody uses 7-bit ASCII anymore. Each character is in fact eight bits long. Second, two seven-bit characters do not fit into one eight-bit buffer. I see that there is some confusion on this point in the comments on the question, so let me attempt to explain further: Seven bits can represent 27 different values, just enough room for the 128 different characters defined by the original ASCII standard. Two seven-bit characters, together, can have 128 * 128 = 16384 = 214 different values; that requires 14 bits to represent, and will not fit into eight bits. You seem to have thought it was only 2 * 128 = 28, which would fit into eight bits, but that's not right; it would mean that once you saw the first character, there were only two possibilities for the second character, not 128.
- 当我直接分配两个一个字节的缓冲区时,我希望它们在内存中直接相邻。因此,我预计每个地址之间的差异是 1(因为内存是按字节寻址的?),而不是我的小程序打印的 8。
正如您自己所观察到的,您的期望是不正确的。
malloc
不需要将连续的分配彼此相邻;事实上,“这些分配是否彼此相邻”可能不是一个有意义的问题。 C 标准不遗余力地avoid要求有any不指向同一数组的两个指针之间的有意义比较。
现在,您正在一个具有“平面地址空间”的系统上工作,所以它is比较连续分配的指针是有意义的(前提是您在自己的大脑中进行操作,而不是使用代码),并且对于分配之间的间隙有一个逻辑解释,但首先我必须指出您打印了错误的地址:
printf("address, buffer1 %p\n", &buffer1);
printf("address, buffer2 %p\n", &buffer2);
这将打印地址指针变量,而不是地址buffers。你应该写
printf("address, buffer1 %p\n", (void *)buffer1);
printf("address, buffer2 %p\n", (void *)buffer2);
(演员阵容void *
是必需的,因为printf
接受一个变量参数列表。)如果你写了你会看到类似的输出
address, buffer1 0x55583d9bb010
address, buffer2 0x55583d9bb030
需要注意的重要一点是,这些分配的不同之处在于sixteen字节,不仅如此,它们都可以被 16 整除。
malloc
需要产生的缓冲区是aligned根据需要any类型,即使您无法将该类型的值放入分配中。如果地址可以被某个字节数整除,则该地址与该字节数对齐。在您的系统上,最大对齐要求是 16;您可以通过运行该程序来确认这一点...
#include <stdalign.h>
#include <stddef.h>
#include <stdio.h>
int main(void) { printf("%zu\n", alignof(max_align_t)); return 0; }
这意味着返回的所有地址malloc
必须能被 16 整除。因此,当你问malloc
对于两个一字节缓冲区,它们之间必须留有十五字节的间隙。这does not意思是malloc
将尺寸四舍五入; C 标准明确禁止您访问间隙中的字节。 (我不知道有任何现代的商业 CPU 可以强制执行该禁令,但调试工具如valgrind http://valgrind.org将会,并且已经有实验性的 CPU 设计可以做到这一点。此外,通常紧接在malloc
块包含内部使用的数据malloc
实施,您不得篡改。)
第二次分配后也存在类似的差距。
- 由于它们在内存中直接相邻,我预计缓冲区 2 会溢出
BB
当我做strcpy(buffer1, BBBB);
作为第一个BB
写给buffer1
其余的溢出到buffer2
.
正如前面讨论的,它们在内存中并不直接相邻,并且每个 B 占用eight位。一个 B 写入您的第一个分配,接下来的 15 个写入两次分配之间的间隙,第 16 个写入第二个分配,之后还有 15 个写入间隙after第二次分配,最后一个 B 和一个 NUL 分配给超出的空间。
我只分配了 2 个字节(因为大小buffer1
and buffer2
总共 2 个字节)。自从BBBBBBBBBBBBBBBBBBBBBBBBB
两者都不适合buffer1
nor buffer2
(因为两者都已经被填满),之后将溢出到下一个内存缓冲区buffer2
。因为我没有分配它,所以我预计会出现分段错误。
我们已经讨论过为什么你的计算不正确,但是你did在第二次分配后一直写入到间隙末尾并进入“空间之外”,那么为什么没有段错误呢?这是因为,在操作系统原语级别,内存以称为“的单元”分配给应用程序。pages https://en.wikipedia.org/wiki/Page_(computer_memory)“,这比您要求的内存量要大。CPU只能检测缓冲区溢出,并在溢出跨越页面边界时触发分段错误。您做得还不够。我在我的电脑,非常相似,我需要写132 KB(一千字节是 1024 字节)(有些人说这应该被称为千字节;他们错了)超出 buffer1 的末尾会出现段错误。我的计算机上的每个页面只有 4 KB,但是malloc
向操作系统请求更大块的内存,因为系统调用的成本很高。
没有收到提示的段错误does not意味着你很安全;你很有可能被打败malloc
的内部数据,或“超越空间”中的另一个分配。如果我采用你的原始程序并添加一个调用free(buffer1)
最后,它崩溃了。