我如何知道内存段的所有零点

Sha*_*ang 4 c c++ linux memory windows

我的意思是,我malloc一段内存,也许1k可能是20bytes ...假设指针是pMem 如何知道所pMem提到的内容是全部Zero\0 .我知道,memcmp但第二个参数应该是另一个内存地址... thanx

Mar*_*ers 20

正如其他人已经建议你可能想要memsetcalloc.

但是,如果您确实想要检查内存区域是否全为零,则可以将其与自身进行比较,但是将其移动一个.

bool allZero = pMem[0] == '\0' && !memcmp(pMem, pMem + 1, length - 1);
Run Code Online (Sandbox Code Playgroud)

其中length是您想要为零的字节数.

  • 是的,在较慢的情况下调用`memcmp`(两个具有不同对齐的缓冲区),以便执行两次必要的内存访问,用于内存绑定任务......真是个好主意! (16认同)
  • 帕斯卡尔,这种讽刺是没有必要的. (4认同)
  • 这比简单的for循环慢得多. (3认同)
  • 你忽略了处理器自己的缓存.你不能真正猜到这种事情,你必须衡量它.它应该是直截了当的,我现在没时间了.如果没有其他人这样做,我会在回家时这样做. (3认同)
  • 虽然很聪明,但这个答案比必要的慢.一个简单的for循环是正确答案(无论是手写还是来自`algorithm`).你*需要*来查看每个内存字节,知道它的每个字节都是0.唯一不合适的方法是你可以做出"如果这个字节是0,接下来的3个是"的假设.这当然只是一个例子而在你的情况下并不存在. (2认同)
  • @Mark抱歉,如果我听起来很讽刺.我确信`memcmp(p,p + 1,size-1)`足够好了,我很惊讶看到这里的评论和其他答案显示某种"它是O(1)因为它是一个库调用,for循环需要更长的时间,因为它必须读取缓冲区"推理. (2认同)

Ste*_*sop 14

由于马克的回答引起了一些争议:

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#ifndef count
    #define count 1000*1000
#endif
#ifndef blocksize
    #define blocksize 1024
#endif

int checkzeros(char *first, char *last) {
    for (; first < last; ++first) {
        if (*first != 0) return 0;
    }
    return 1;
}

int main() {
    int i;
    int zeros = 0;

    #ifdef EMPTY
        /* empty test loop */
        for (i = 0; i < count; ++i) {
            char *p = malloc(blocksize);
            if (*p == 0) ++zeros;
            free(p);
        }
    #endif

    #ifdef LOOP
        /* simple check */
        for (i = 0; i < count; ++i) {
            char *p = malloc(blocksize);
            if (checkzeros(p, p + blocksize)) ++zeros;
            free(p);
        }
    #endif

    #ifdef MEMCMP
        /* memcmp check */
        for (i = 0; i < count; ++i) {
            char *p = malloc(blocksize);
            if (*p == 0 && !memcmp(p, p + 1, blocksize - 1)) ++zeros;
            free(p);
        }
    #endif

    printf("%d\n", zeros);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

结果(cygwin,Windows XP,Core 2 Duo T7700在2.4 GHz):

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DEMPTY && time ./cmploop
1000000

real    0m0.500s
user    0m0.405s
sys     0m0.000s

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DLOOP && time ./cmploop
1000000

real    0m1.203s
user    0m1.233s
sys     0m0.000s

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DMEMCMP && time ./cmploop
1000000

real    0m2.859s
user    0m2.874s
sys     0m0.015s
Run Code Online (Sandbox Code Playgroud)

因此,对于我来说,memcmp大约需要(2.8 - 0.4)/(1.2 - 0.4)= 3倍.看到其他人的结果很有意思 - 我的所有malloced内存都归零,所以我总是得到每次比较的最坏情况时间.

对于较小的块(以及更多的块),比较时间不太重要,但memcmp仍然较慢:

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DEMPTY -Dblocksize=20 -Dcount=10000000 && time ./cmploop
10000000

real    0m3.969s
user    0m3.780s
sys     0m0.030s

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DLOOP -Dblocksize=20 -Dcount=10000000 && time ./cmploop
10000000

real    0m4.062s
user    0m3.968s
sys     0m0.015s

$ gcc-4 cmploop.c -o cmploop -pedantic -Wall -O2 -DMEMCMP -Dblocksize=20 -Dcount=10000000 && time ./cmploop
10000000

real    0m4.391s
user    0m4.296s
sys     0m0.015s
Run Code Online (Sandbox Code Playgroud)

我对此感到有些惊讶.我期望memcmp至少能够竞争,因为我希望它能够内联并针对编译时已知的小尺寸进行优化.即使更改它以便它在开始时测试一个int然后再测试16个字节的memcmp,以避免未对齐的最坏情况,也不会加快它的速度.


Dou*_*der 9

如果你正在测试它,然后只在它为0时才使用它,那么请注意你有一个竞争条件,因为@Mark Byers建议的方法没有原子测试/设置操作.在这种情况下,很难让逻辑正确.

如果你想将它归零,如果它还不是零,那么只需将其设置为零,因为它会更快.


Kir*_*sky 7

C++解决方案:

bool all_zeroes = 
  (find_if( pMem, pMem+len, bind2nd(greater<unsigned char>(), 0)) == (pMem+len));
Run Code Online (Sandbox Code Playgroud)


Rob*_*edy 5

如您所述,memcmp将一块内存与另一块内存进行比较.如果你已经知道的另一块内存全部为零,那么你可以使用该参考块与候选块进行比较,看它们是否匹配.

听起来你没有另一块记忆.你只有一个,你想知道它是否全部为零.标准库不提供这样的功能,但是编写自己的函数很容易:

bool is_all_zero(char const* mem, size_t size)
{
  while (size-- > 0)
    if (*mem++)
      return false;
  return true;
}
Run Code Online (Sandbox Code Playgroud)

如果你想分配一个新的内存块并立即将其全部归零,那么请使用calloc而不是malloc.如果您要将内存块设置为全零,则使用memsetstd::fill.

  • @Macroideal除非硬件有特殊支持,否则检查缓冲区是否包含全零值需要读取缓冲区.没有其他办法了.至少在这个答案中,缓冲区只读一次. (7认同)