为什么malloc(1)用于存储4字节整数?

时间:2017-01-24 08:01:38

标签: c memory malloc

据我所知,malloc(x)返回一个x字节长的内存块。

所以为了存储一个4字节的整数,我会这样做:

    int *p = (int *)malloc(4);
    *p = 100;

因为sizeof(int)为我返回4。

但是,如果我这样做:

    int *p = (int *)malloc(1);
    *p = 100;

它似乎完全相同,没有存储值的问题。

为什么malloc()请求的内存量似乎不重要?不应该是4字节整数需要malloc(4)吗?

8 个答案:

答案 0 :(得分:4)

如果这适用于您的情况,它只是偶然的工作,并不保证工作。它是未定义的行为(比较this SO question),一切都可能发生。

您期望发生什么?你的程序崩溃了?

如果您更频繁地拨打for (int i = 0; i <= dt.Rows.Count; i++) for (int i = 0; i < dt.Rows.Count; i++) ,可能仍会发生这种情况。 malloc通常比请求的字节数多一些,并使用额外的空间进行管理(所有内存块的链表,内存块的大小)。如果你在分配的块之前或之后写了一些字节,那么你很可能会混淆内部管理结构,而free的后续malloc会崩溃。

如果malloc内部总是分配最少n个字节,那么如果访问字节n + 1,程序可能只会崩溃。此外,操作系统通常仅基于页面保护存储器。如果一个页面的大小为512字节,并且您的malloc-ed字节位于页面的中间,那么您的进程可能能够读写页面的其余部分,并且只会在访问下一个内存页面时崩溃。但请记住:即使这有效,也是未定义的行为。

答案 1 :(得分:2)

  

它似乎完全相同,没有存储值的问题。

您使用代码调用未定义的行为,因此您无法确定它是否有效。为了为整数分配内存,你应该这样做:

int *p;
p = malloc(sizeof (*p) ); //you can use sizeof(*p) as p is already declared and here you use the size of its content, which is actually the size of an int
if (p != NULL)
    *p = 100;

答案 2 :(得分:2)

C编程语言让你能够用脚射击自己。

它故意给程序员带来负担,他们应该知道他们在做什么。从广义上讲,原因是要实现性能,可读性和可移植性。

代码的行为是未定义。如果要求1个字节,则期望只返回一个可用字节。事实上,操作系统和C运行时库似乎给你的回馈不过是一个奇怪的特点。

在其他情况下,编译器可能只是吃你的猫。

最后,在malloc的调用中使用int,而不是硬编码sizeof(int)类型的大小:在许多系统上sizeof(int)是2,4,这是常见的,并且标准允许所有大于1的值。在您的情况下,可以使用sizeof(*p)sizeof。有些人喜欢后者,因为那时你并没有在sizeof(*p)调用中硬编码变量的类型,所以要防止可能的变量类型更改。 (注意p是编译时可评估的并且使用静态类型信息;因此它可以在[ 2017-01-24 08:27:50.0090 24342/7f8d9164f780 apache2/Hooks.cpp:718 ]: Unexpected error in mod_passenger: Cannot connect to the helper agent at /tmp/passenger.1.0.20176/generation-0/request Backtrace: in 'Passenger::FileDescriptor Hooks::connectToHelperAgent()' (Hooks.cpp:283) in 'int Hooks::handleRequest(request_rec*)' (Hooks.cpp:532) [Tue Jan 24 08:36:41.659372 2017] [mpm_prefork:notice] [pid 20176] AH00169: caught SIGTERM, shutting down [ 2017-01-24 08:36:41.6769 20188/7ff6b3484780 agents/LoggingAgent/Main.cpp:289 ]: Caught signal, exiting... [ 2017-01-24 08:36:43.6948 29025/7f612a691740 agents/Watchdog/Main.cpp:538 ]: Options: { 'analytics_log_user' => 'nobody', 'default_group' => 'nogroup', 'default_python' => 'python', 'default_ruby' => '/usr/bin/ruby1.9.1', 'default_ [ 2017-01-24 08:36:43.6976 29028/7ff0c7127740 agents/HelperAgent/Main.cpp:643 ]: PassengerHelperAgent online, listening at unix:/tmp/passenger.1.0.29024/generation-0/request [ 2017-01-24 08:36:43.7020 29033/7fe594edb780 agents/LoggingAgent/Main.cpp:321 ]: PassengerLoggingAgent online, listening at unix:/tmp/passenger.1.0.29024/generation-0/logging [ 2017-01-24 08:36:43.7021 29025/7f612a691740 agents/Watchdog/Main.cpp:728 ]: All Phusion Passenger agents started! [ 2017-01-24 08:36:43.7205 29047/7fa61ed1c740 agents/Watchdog/Main.cpp:538 ]: Options: { 'analytics_log_user' => 'nobody', 'default_group' => 'nogroup', 'default_python' => 'python', 'default_ruby' => '/usr/bin/ruby1.9.1', 'default_ [ 2017-01-24 08:36:43.7234 29051/7f78162fe740 agents/HelperAgent/Main.cpp:643 ]: PassengerHelperAgent online, listening at unix:/tmp/passenger.1.0.29045/generation-0/request [ 2017-01-24 08:36:43.7277 29057/7f83146cc780 agents/LoggingAgent/Main.cpp:321 ]: PassengerLoggingAgent online, listening at unix:/tmp/passenger.1.0.29045/generation-0/logging [ 2017-01-24 08:36:43.7279 29047/7fa61ed1c740 agents/Watchdog/Main.cpp:728 ]: All Phusion Passenger agents started! [Tue Jan 24 08:36:43.737820 2017] [mpm_prefork:notice] [pid 29045] AH00163: Apache/2.4.6 (Ubuntu) Phusion_Passenger/4.0.40 PHP/5.5.3-1ubuntu2.2 configured -- resuming normal operations [Tue Jan 24 08:36:43.737856 2017] [core:notice] [pid 29045] AH00094: Command line: '/usr/sbin/apache2' App 29105 stdout: App 29105 stderr: /var/lib/gems/1.9.1/gems/passenger-4.0.40/lib/phusion_passenger/platform_info.rb:352: warning: Insecure world writable dir /usr/local/bin in PATH, mode 040777 [ 2017-01-24 08:36:50.8464 29051/7f7816207700 Pool2/SmartSpawner.h:301 ]: Preloader for /usr/share/redmine started on PID 29105, listening on unix:/tmp/passenger.1.0.29045/generation-0/backends/preloader.29105 App 29145 stdout: 本身&#34;存在&#34;之前使用,如果你明白我的意思。)

答案 3 :(得分:1)

为此,我们应该知道malloc函数在内部如何工作。为了动态分配内存,每个操作系统都使用系统调用。我们可以使用这些系统调用动态分配内存。这些系统调用与一个操作系统不同。

因此,一个操作系统的系统调用可能不适用于另一操作系统。而且,如果我们使用系统调用动态分配内存,那么我们的程序将依赖于平台。因此,为了避免这种依赖性,我们使用malloc函数。现在,malloc函数负责根据操作系统进行适当的系统调用以动态分配内存。

因此,malloc本身会调用系统调用,这将是一个非常缓慢的过程,因为每次我们请求动态内存时,它都必须利用系统调用。为了避免这种情况,每当我们请求动态内存时,它通常都会分配额外的内存,以便下次可以避免系统调用并可以使用先前分配的内存的剩余块。这就是为什么您的程序在malloc分配额外的内存时工作的原因。

答案 4 :(得分:0)

通常malloc的实现方式是,它分配的内存大小不小于段落大小等于16个字节。 因此,当您需要例如4个字节的内存{{1}}实际分配16个字节时。但是,此行为未在C标准中描述,您可能不会依赖它。结果,这意味着您显示的程序具有未定义的行为。

答案 5 :(得分:0)

我认为这是因为填充,即使你正在调用malloc(1)填充字节随内存一起提供。 请查看此链接http://www.delorie.com/gnu/docs/glibc/libc_31.html

答案 6 :(得分:0)

malloc,因为来自C运行时或OS内核的所有内存块分配函数都针对内存访问和对象对齐进行了优化。

此外,malloc具体而言,在分配的空间前分配一个隐藏的控制块,以跟踪分配(所需空间,空间分配等)。

malloc还必须保证分配的内存地址适合任何存储对象,这意味着该块将以8,16,32甚至64或8开始128字节边界取决于处理器和一般来自硬件(即一些特殊MMU)。边界也取决于访问速度,某些处理器具有不同的行为,具有不同的存储器访问(1,2,4,8,...字节)和地址边界。这种约束驱动malloc代码规范和分配器逻辑内存块分区。

在实际的一面让我们考虑一个X86处理器的分配器,它通常会返回一个在8字节边界(32位代码)上对齐的块,这对int,float和偶数都很有用。为此,malloc将可用内存区域划分为最小分配空间的“块”。当您分配甚至1个字节时,该函数至少分配一个块。最终这个块可以托管一个整数,甚至是一个double,,但它依赖于实现,你不能认为它是确定性的,因为在同一个函数的未来版本中,行为可以改变。

现在,我希望,很清楚,因为您的代码似乎有效,请记住这是未定义的行为,您必须保留它。 IT现在可以工作,而不是下一次修订,它可能会在某些硬件上崩溃,而不会在另一台处理器或机器上崩溃。

答案 7 :(得分:0)

简单地说,当你为 int 分配 1 个字节时,后面还有 3 个字节实际上没有分配给它,但你仍然可以使用它们。您很幸运,这些在您的测试期间没有被其他东西改变,并且它没有覆盖任何重要的东西(或者可能是)。所以本质上,一旦其他东西需要这 3 个字节,这将导致错误 - 始终分配正确的大小。