2

我需要将文件中不同大小的记录归零。为此,我目前正在分配虚拟记录,memset将它们归零,然后将它们传递给写入函数。

是否有一些区域可以保证始终归零(并且大小足够大),而我可以指向它,从而消除重复分配和归零内存的需要?

4

9 回答 9

8

如果记录大小有合理的上限,请分配一个包含零的全局只读变量。(因为它是一个静态持续时间对象,它会自动初始化为零。)

const unsigned char zero_filled_buffer[MAX_RECORD_SIZE]; /*at file scope*/

如果 write 函数是 Cfwrite或 POSIXwrite或其他函数,您可以(必须, for write)在循环中调用它,因此缓冲区不必与最大记录一样大,只要与您的最大块一样大马上写。

在典型的托管实现下,这样的变量将在您的可执行文件中占用零空间。添加:请注意,就 C 标准而言,上面的声明完全等同于,const unsigned char zero_filled_buffer[MAX_RECORD_SIZE] = {0};但是如果您显式添加,则某些编译器(包括 gcc)在可执行文件中包含零,= {0}但如果您不使用初始化程序,则不会。

具有虚拟内存的系统上的智能程序加载器可以利用虚拟内存系统为所有此类对象使用物理 RAM 的单个共享只读零填充页面;不知道有没有实际操作。添加:例如,Linux (Debian lenny amd64) 没有。

另一种 POSIX 方法是mmap文件并调用memset零填充缓冲区。

于 2010-08-15T15:27:55.030 回答
3

参见calloc

calloc()函数应为元素数组分配未使用的空间,nelem每个元素的字节大小为elsize。该空间应初始化为所有位0

或者(我没有尝试过),如果您根本不想要任何分配,您可以open和/或从中mmap /dev/zero读取record_size块并将它们写入您正在覆盖记录的文件中。

于 2010-08-15T14:50:55.003 回答
2

至少在linux上分配内存mmap()会给你一个零填充的缓冲区。缺点是您不能只分配所需的内存,而只能分配页面大小的倍数

#include <unistd.h>
long sz = sysconf(_SC_PAGESIZE);
于 2010-08-15T15:05:19.460 回答
1

是的,只需为任何这些记录分配一个足够大的块,然后将其归零一次。每次都将该块的地址传递给您的写入函数,并使用您实际想要清零的记录大小。将缓冲区传递给写入不会使其过期或任何事情。请注意, write 也不会释放您传递的缓冲区;这取决于你。

于 2010-08-15T14:48:03.730 回答
1

如果您想要一个始终归零的大内存区域,您应该自己分配它并将其 memset 为零。没有解决这个问题,但你应该只需要做一次。确保它至少与您在任何时候需要的最大归零内存一样大。

然后,每当您需要将指针传递给归零内存时,您都可以将指针传递给您分配的该块内。

于 2010-08-15T14:48:19.547 回答
1

如前所述,您只需分配一次您将需要的最大区域;您可以在任何需要该大小或更小的区域时传递它。

在大多数实现中,地址空间的任何部分都没有映射到 RAM,但在读取时会无害地读取零。这样的东西可能很好,但我不知道。

在一些嵌入式系统中,我编写了闪存写入例程,因此,如果给定一个空指针,它们将假定源数据(取决于应用程序)全是 FF,因为我有时确实需要清除一大块一个文件,并且让最终的写入代码处理空指针情况意味着查找和分配闪存块的代码可以在写有意义的数据情况和写空白数据的情况之间共享。一个警告是,如果将写入分成多个部分,则在将空指针传递给 I/O 写入之前,不得将偏移量添加到空指针。

于 2010-08-15T15:31:14.837 回答
0

这是保证工作的运行时可能性(使用 编译gcc zeroed_mem_region.c -Wall -std=gnu99):

#include <sys/mman.h>
#include <assert.h>
#include <stdio.h>

size_t const zeroed_size = 512;
char const *zeroed;

int main()
{
    zeroed = mmap(
            NULL,
            zeroed_size,
            PROT_READ,
            MAP_PRIVATE|MAP_ANONYMOUS,
            -1,
            0);
    printf("zeroed region at %p\n", zeroed);
    for (size_t i = 0; i < zeroed_size; ++i) {
        assert(zeroed[i] == 0);
    }
    printf("testing for writability\n");
    ((char *)zeroed)[0] = 1;
    return 0;
}

请注意, zeroedchar const *用于测试,实际上这将是void const *.

优点

  • 避免使用 malloc 分配器
  • 保证区域不可写(生成SIGSEGV
  • 比使用 malloc 更快
  • 不会在可执行文件中添加废话
  • 不需要 memset 步骤(检查mmap(2)

缺点

  • Unix/Linux 特定(Linux 2.4 以来的匿名映射)
  • 减少编译器优化的可能性(尽管这方面显然不存在)
于 2010-08-16T05:06:07.187 回答
0

使用系统信息 API 获取系统页面大小(我只是不记得确切的名称),分配 1 页内存,将其设置为零,一遍又一遍地顺序写入。

于 2010-08-15T14:47:36.957 回答
0

写入函数的速度将比 memset 慢几个数量级。

简介吧!

* 即使使用闪存驱动器

于 2010-08-15T14:54:07.760 回答