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

时间:2009-12-09 07:19:18

标签: c++ c windows linux memory

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

14 个答案:

答案 0 :(得分:20)

正如其他人已经建议您可能需要memsetcalloc

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

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

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

答案 1 :(得分: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;
}

结果(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

因此,对于我来说,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

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

答案 2 :(得分:9)

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

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

答案 3 :(得分:7)

C ++解决方案:

bool all_zeroes = 
  (find_if( pMem, pMem+len, bind2nd(greater<unsigned char>(), 0)) == (pMem+len));

答案 4 :(得分:5)

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

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

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

如果您想分配一个新的内存块并立即将其全部归零,请使用calloc代替malloc。如果您要将内存块设置为全零,请使用memsetstd::fill

答案 5 :(得分:3)

如果要分配内存中的所有0,可以使用calloc

答案 6 :(得分:3)

对于大缓冲区:

typedef int tNativeInt;  // __int64 on 64 bit platforms with 32 bit ints

// test most of the buffer using CPU Word size
tNativeInt * ptr = reinterpret_cast<tNativeInt *>(buffer);
tNativeInt * end = ptr + bufSize / sizeof(tNativeInt);
for(;ptr < end;++ptr)
  if (*ptr != 0)
    return false;

// check remainder
char * ptrc = reinterpret_cast<char *>(ptr);
char * endc = ptrc + bufSize % sizeof(tNativeInt);
for(; ptrc<endc; ++ptrc)
  if (*ptrc != 0)
    return false;

说明:
测试完整CPU字的核心优化 - 读取一个字通常和单个字节一样昂贵。

代码假定缓冲区已完全对齐(即地址是CPU字大小的倍数)。如果不是,则需要在块测试之前放置类似于“余数”的块。

对于小缓冲区,附加代码当然会慢一些 - 但是,在这种情况下,人们通常认为这些短暂的持续时间并不重要。

如果您愿意,您当然可以使用std :: find_if替换循环。


效果:1:3.9

(VS 2008,/ Ox / Ot,2,47 +/- 0,11 vs. 0,63 +/- 0,19,超过256000字节10000次重复, 首先删除了超过15次重复的统计数据)

讨论:根据我从分析C / C ++到汇编的经验,我不会期望编译器进行这种优化 - 因为它是对小size的一种悲观,以及优化的可能性那种类型很少而且很远。大致为4的因素证实了这一点 - 正如看反汇编一样。

此外,对于大多数应用程序来说,总时间可以忽略不计,缓存未命中率会更差,并且会影响两个版本。

[编辑]为了它的乐趣:

以1:1.4 重叠memcmp时钟,这比单字节检查要好得多(让我感到有些惊讶)。

请注意,未对齐的读取使得强烈依赖于平台。

答案 7 :(得分:2)

如果您需要将内存设为零,只需将memset()设为零;检查它是否为零是浪费时间,因为它可能不是,你最终会做更多的工作,检查然后设置。

但是,如果你真的想要有效地检查一个内存区域以查看它是否全为零,你可以memcmp()对着其他已知的内容全部为零。例如,你可以分配和归零一个内存块,然后保留一个指向它的指针,用于与其他内存块进行比较。

答案 8 :(得分:2)

另一种C ++解决方案,比Kirill稍微简单一些。但是,它的效率稍低,因为即使该序列包含非零元素,它也会遍历整个序列。

bool all_zeroes = std::count(pMem, pMem + length, 0) == length;

答案 9 :(得分:2)

借助Steve Jessops代码寻找乐趣,我找到了这个变种

int checkzeros(char *f, char *l) {
        char a = 0;
        while (f < l) {
                a |= *f++;
        }
        if (a) {
                return 0;
        }
        return 1;
}

快约50%(核心循环中没有分支)。所有的错误都是我的。

[编辑]:史蒂夫指出,这个版本有一个很好的最坏情况和一个可怕的 最好的情况(因为它们是相同的)。仅在完全归零的缓冲区时才使用它 是唯一需要快速的案例。

答案 10 :(得分:2)

更多基准:

大致基于Steve Jessop的样本。 我测试了以下内容:

  • 天真的mem​​cmp(分配一个单独的零块,并与之比较)
  • “聪明”memcmp(将块与自身进行比较,移位一次)
  • std::find_if
  • 检查每个字节的简单循环

这些都没有对数组作出任何假设,只是接受并处理一组字符。

最后,我制作了第五个版本,它将数组转换为int,然后比较它们。 (这个显然假设数组的大小可以被sizeof(int)整除,所以它不太通用。但我添加它来证明使用合理的块大小比使用memcpy更有用的优化和字节比较。

哦,请注意我刚刚把这个测试快速打到了一起,我用了一个Windows计时器因为我很懒。 :)

#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>

#include <windows.h>

enum {
    count = 1000*1000,
    blocksize = 1024
};

bool test_simple_loop(char* p){
    for (int i = 0; i < blocksize; ++i) {
        if (p[i] != 0) { return false; }
    }
    return true;
}

bool test_memcmp_clever(char* p){
    return *p == 0 && memcmp(p, p + 1, blocksize - 1) == 0;
}
bool test_memcmp_naive(char* p, char* ref){
    return memcmp(p, ref, blocksize) == 0;
}

struct cmp {
    template <typename T>
    bool operator()(T& x) {
        return x != 0;
    }
};
bool test_find_if(char* p){
    return std::find_if(p, p+blocksize, cmp()) == p+blocksize;
}

bool test_find_if_big(int* p){
    return std::find_if(p, p+blocksize, cmp()) == p+blocksize;
}

int main() {

    bool res = true;

    char *p = new char[blocksize];
    char *ref = new char[blocksize];

    std::fill(ref, ref+blocksize, 0);
    std::fill(p, p+blocksize, 0); // ensure the worst-case scenario, that we have to check the entire buffer. This will also load the array into CPU cache so the first run isn't penalized

    DWORD times[5];
    DWORD start;

    start = GetTickCount();
    for (int i = 0; i != count; ++i) {
        res &= test_memcmp_naive(p, ref);
    }
    times[0] = GetTickCount() - start;
    start = GetTickCount();
    for (int i = 0; i != count; ++i) {
        res &= test_memcmp_clever(p);
    }
    times[1] = GetTickCount() - start;
    start = GetTickCount();
    for (int i = 0; i != count; ++i) {
        res &= test_find_if(p);
    }
    times[2] = GetTickCount() - start;
    start = GetTickCount();
    for (int i = 0; i != count; ++i) {
        res &= test_simple_loop(p);
    }
    times[3] = GetTickCount() - start;
    start = GetTickCount();
    for (int i = 0; i != count; ++i) {
        res &= test_find_if_big(reinterpret_cast<int*>(p));
    }
    times[4] = GetTickCount() - start;

    delete[] p;
    delete[] ref;

    printf("%d\n", res);
    printf("%d\n%d\n%d\n%d\n%d\n", times[0], times[1], times[2], times[3], times[4]);
}

我的结果是:(以毫秒为单位,一百万次运行)

Naive memcmp: 546
"Clever" memcmp: 530
`find_if<char>`: 1466
Simple loop: 1358
`find_if<int`>: 343

我认为要点非常明确: 任何进行逐字节比较的东西都很慢。真的很慢。 Memcmp或多或少都可以,但它远非完美。它太笼统而不是最佳。

解决此问题的最有效方法是尽可能多地处理数据。 char只是愚蠢。 int是一个良好的开端,但64位或128位读取的表现可能会好得多。

答案 11 :(得分:1)

repe.S

.globl repe_scasb
repe_scasb:
#if defined(__i386__)
        push   %edi
        mov    $0x0,%al
        mov    0xc(%esp),%ecx
        mov    0x8(%esp),%edi
        sub    %edi,%ecx
        repe scasb
        pop    %edi
        sete   %al
        ret
#elif defined(__amd64__)
        mov    $0x0,%al
        mov    %rsi,%rcx
        sub    %rdi,%rcx
        repe scasb
        sete   %al
        ret
#else
#  error "repe_scasb not defined for current architecture"
#endif

.globl repe_scas
repe_scas:
#if defined(__i386__)
        push   %edi
        mov    $0x0,%eax
        mov    0xc(%esp),%edx
        mov    0x8(%esp),%edi
        sub    %edi,%edx
repe_scas4:
        test   $0x3,%di
        jnz    repe_scas2
        cmp    $0x4,%edx
        jl     repe_scas2
        mov    %edx,%ecx
        shr    $0x2,%ecx
        repe scasl
        jne    repe_scas0
        and    $0x3,%edx
repe_scas2:
        test   $0x1,%di
        jnz    repe_scas1
        cmp    $0x2,%edx
        jl     repe_scas1
        scasw
        jnz    repe_scas0
        sub    $0x2,%edx
        jmp    repe_scas4
repe_scas1:
        test   %edx,%edx
        jz     repe_scas0
        scasb
        jnz    repe_scas0
        sub    $0x1,%edx
        jmp    repe_scas4
repe_scas0:
        pop    %edi
        sete   %al
        ret
#elif defined(__amd64__)
        mov    $0x0,%eax
        sub    %rdi,%rsi
repe_scas8:
        test   $0x7,%di
        jnz    repe_scas4
        cmp    $0x8,%rsi
        jl     repe_scas4
        mov    %rsi,%rcx
        shr    $0x3,%rcx
        repe scasq
        jne    repe_scas0
        and    $0x7,%rsi
repe_scas4:
        test   $0x3,%di
        jnz    repe_scas2
        cmp    $0x4,%rsi
        jl     repe_scas2
        scasl
        jnz    repe_scas0
        sub    $0x4,%rsi
        jmp    repe_scas8
repe_scas2:
        test   $0x1,%di
        jnz    repe_scas1
        cmp    $0x2,%rsi
        jl     repe_scas1
        scasw
        jnz    repe_scas0
        sub    $0x2,%rsi
        jmp    repe_scas8
repe_scas1:
        test   %rsi,%rsi
        jz     repe_scas0
        scasb
        jnz    repe_scas0
        sub    $0x1,%rsi
        jmp    repe_scas8
repe_scas0:
        sete   %al
        ret
#else
#  error "repe_scas not defined for current architecture"
#endif

test.c

#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

static int compar_double(const void *a, const void *b) {
    double diff = *(const double *)a - *(const double *)b;
    if (diff < 0) return -1;
    if (diff > 0) return 1;
    return 0;
}

static bool bit_or(const void *first, const void *last) {
    uint8_t a;
    for (a = 0; first < last; first = (const uint8_t *)first + 1)
        a |= *(const uint8_t *)first;
    return !a;
}

static bool use_memcmp(const void *first, const void *last) {
    return first >= last
        || !(((uint8_t *)first)[0]
        || memcmp(first, (const uint8_t *)first + 1,
            (const uint8_t *)last - (const uint8_t *)first - 1));
}

static bool check_bytes(const void *first, const void *last) {
    while (first < last) {
        if (*(const uint8_t *)first) return false;
        first = (const uint8_t *)first + 1;
    }
    return true;
}

static bool check_aligned(const void *first, const void *last) {
    switch ((uintptr_t)first & 7) while (first < last) {
        case 0:
            if (last - first >= 8) {
                if (*(const uint64_t *)first) return false;
                first = (const uint64_t *)first + 1;
                continue;
            }
        case 4:
            if (last - first >= 4) {
                if (*(const uint32_t *)first) return false;
                first = (const uint32_t *)first + 1;
                continue;
            }
        case 2: case 6:
            if (last - first >= 2) {
                if (*(const uint16_t *)first) return false;
                first = (const uint16_t *)first + 1;
                continue;
            }
        case 1: case 3: case 5: case 7:
            if (*(const uint8_t *)first) return false;
            first = (const uint8_t *)first + 1;
    }
    return true;
}

bool repe_scasb(const void *, const void *);
bool repe_scas(const void *, const void *);

static const struct {
    const char name[16];
    bool (*fn)(const void *, const void *);
} functions[] = {
    { "bit_or", bit_or },
    { "use_memcmp", use_memcmp },
    { "check_bytes", check_bytes },
    { "check_aligned", check_aligned },
    { "repe_scasb", repe_scasb },
    { "repe_scas", repe_scas },
};

#define REPS 999
#define BYTECYCLES 0xFFFF
void time_functions(const char *s, const void *first, const void *last, bool expect) {
    unsigned i, cycles = BYTECYCLES / (last - first) + 1;
    char seps[sizeof(functions) / sizeof(*functions)];
    double times[sizeof(functions) / sizeof(*functions)][REPS];

    for (i = 0; i < sizeof(functions) / sizeof(*functions); i++) {
        unsigned j;

        seps[i] = '/';
        for (j = 0; j < REPS; j++) {
            unsigned k;
            struct timespec start, finish;
            clock_gettime(CLOCK_MONOTONIC, &start);
            for (k = 0; k < cycles; k++)
                if (functions[i].fn(first, last) != expect) seps[i] = '!';
            clock_gettime(CLOCK_MONOTONIC, &finish);
            times[i][j] = ((finish.tv_sec - start.tv_sec) +
                    (finish.tv_nsec - start.tv_nsec) / 100000000.) / cycles;
        }
    }

    fputs(s, stdout);
    for (i = 0; i < sizeof(functions) / sizeof(*functions); i++) {
        qsort(times[i], REPS, sizeof(double), compar_double);
        printf("|%8.2e%c%8.2e", times[i][REPS / 4], seps[i], times[i][3 * REPS / 4]);
    }
    putchar('\n');
}

static size_t sizes[] = {0x7, 0x7, 0x7, 0x7, 0x400, 0x1000, 0x100000};
static uint8_t storage[0x100000];

int main() {
    unsigned i, j, k;

    fputs("      ", stdout);
    for (i = 0; i < sizeof(functions) / sizeof(*functions); i++)
        printf(" |%16.16s", functions[i].name);
    fputs("\n-------", stdout);
    for (i = 0; i < sizeof(functions) / sizeof(*functions); i++)
        fputs("+-----------------", stdout);
    putc('\n', stdout);

    for (j = 0, k = 8; j < sizeof(sizes) / sizeof(*sizes); j++) {
        char test[8];
        if (k /= 2) snprintf(test, sizeof(test), "0x%zX+%u", sizes[j], k);
        else snprintf(test, sizeof(test), "0x%zX", sizes[j]);
        printf("%-7.7s|\n", test);

        memset(storage + k, 0, sizes[j]);
        time_functions("  zero ", storage + k, storage + k + sizes[j], true);

        storage[k + sizes[j] - 1] = 1;
        time_functions("  last ", storage + k, storage + k + sizes[j], false);

        storage[k + sizes[j] / 2] = 1;
        time_functions("  half ", storage + k, storage + k + sizes[j], false);

        memset(storage + k, ~0, sizes[j]);
        time_functions("  first", storage + k, storage + k + sizes[j], false);
    }

    return 0;
}

Makefile

CFLAGS ?= -g -O3 -W -Wall -Wextra
LIBS = -lrt
SRC := test.c repe.S
all: test32 test64
test32: $(SRC)
        $(CC) -m32 $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
test64: $(SRC)
        $(CC) -m64 $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
time: time32 time64
time32: test32
        ./test32
time64: test64
        ./test64
.PHONY: all time time32 time64

此测试显示的是第一个四分位数和第三个四分位数的时间,而不仅仅是平均值,但似乎系统相当一致(在±2%范围内变化)。

$ make time
cc -m32 -g -O3 -W -Wall -Wextra  -o test32 test.c repe.S -lrt
./test32
       |          bit_or |      use_memcmp |     check_bytes |   check_aligned |      repe_scasb |       repe_scas
-------+-----------------+-----------------+-----------------+-----------------+-----------------+-----------------
0x7+4  |
  zero |1.09e-07/1.09e-07|2.09e-07/2.11e-07|1.66e-07/1.68e-07|1.35e-07/1.74e-07|1.83e-07/1.86e-07|2.00e-07/2.06e-07
  last |1.09e-07/1.09e-07|2.09e-07/2.12e-07|1.00e-07/1.00e-07|1.18e-07/1.18e-07|1.83e-07/1.85e-07|1.83e-07/1.85e-07
  half |1.09e-07/1.09e-07|1.79e-07/1.84e-07|7.42e-08/7.42e-08|6.98e-08/6.98e-08|1.57e-07/1.59e-07|1.39e-07/1.40e-07
  first|1.09e-07/1.09e-07|6.11e-08/6.11e-08|4.81e-08/4.81e-08|6.98e-08/6.99e-08|1.22e-07/1.27e-07|1.39e-07/1.42e-07
0x7+2  |
  zero |1.09e-07/1.09e-07|2.09e-07/2.11e-07|1.66e-07/1.71e-07|1.31e-07/1.57e-07|1.83e-07/1.85e-07|2.00e-07/2.06e-07
  last |1.09e-07/1.09e-07|2.09e-07/2.14e-07|1.00e-07/1.00e-07|1.22e-07/1.24e-07|1.83e-07/1.88e-07|1.83e-07/1.83e-07
  half |1.09e-07/1.09e-07|1.79e-07/1.80e-07|7.42e-08/7.42e-08|8.72e-08/8.72e-08|1.57e-07/1.59e-07|1.61e-07/1.66e-07
  first|1.09e-07/1.09e-07|6.11e-08/6.11e-08|4.81e-08/4.81e-08|6.55e-08/6.55e-08|1.22e-07/1.22e-07|5.82e-08/5.82e-08
0x7+1  |
  zero |1.09e-07/1.09e-07|2.09e-07/2.14e-07|1.66e-07/1.66e-07|1.09e-07/1.42e-07|1.83e-07/1.88e-07|2.05e-07/2.07e-07
  last |1.09e-07/1.09e-07|2.09e-07/2.14e-07|1.00e-07/1.00e-07|1.00e-07/1.00e-07|1.83e-07/1.87e-07|1.92e-07/1.97e-07
  half |1.09e-07/1.09e-07|1.79e-07/1.81e-07|7.42e-08/7.42e-08|7.85e-08/7.86e-08|1.57e-07/1.61e-07|1.92e-07/1.97e-07
  first|1.09e-07/1.09e-07|6.11e-08/6.11e-08|4.81e-08/4.81e-08|5.24e-08/5.24e-08|1.22e-07/1.22e-07|6.55e-08/6.55e-08
0x7    |
  zero |1.09e-07/1.09e-07|2.09e-07/2.14e-07|1.66e-07/1.71e-07|1.52e-07/1.79e-07|1.83e-07/1.88e-07|2.00e-07/2.06e-07
  last |1.09e-07/1.09e-07|2.09e-07/2.14e-07|1.00e-07/1.00e-07|1.44e-07/1.70e-07|1.83e-07/1.88e-07|1.83e-07/1.85e-07
  half |1.09e-07/1.09e-07|1.79e-07/1.79e-07|7.42e-08/7.42e-08|7.85e-08/7.85e-08|1.57e-07/1.57e-07|1.39e-07/1.39e-07
  first|1.09e-07/1.09e-07|6.11e-08/6.11e-08|4.81e-08/4.81e-08|7.85e-08/7.85e-08|1.22e-07/1.22e-07|1.39e-07/1.39e-07
0x400  |
  zero |9.06e-06/9.06e-06|9.97e-06/9.97e-06|1.79e-05/1.81e-05|2.93e-06/2.93e-06|9.06e-06/9.07e-06|2.41e-06/2.41e-06
  last |9.06e-06/9.06e-06|9.97e-06/9.97e-06|1.80e-05/1.80e-05|2.39e-06/2.39e-06|9.06e-06/9.07e-06|2.40e-06/2.40e-06
  half |9.06e-06/9.06e-06|5.08e-06/5.08e-06|9.06e-06/9.06e-06|1.29e-06/1.29e-06|4.62e-06/4.62e-06|1.30e-06/1.30e-06
  first|9.06e-06/9.06e-06|9.25e-08/9.67e-08|8.34e-08/9.67e-08|1.05e-07/1.06e-07|1.58e-07/1.58e-07|1.75e-07/1.75e-07
0x1000 |
  zero |3.59e-05/3.59e-05|3.95e-05/3.95e-05|7.15e-05/7.15e-05|1.14e-05/1.14e-05|3.59e-05/3.59e-05|9.20e-06/9.20e-06
  last |3.59e-05/3.59e-05|3.95e-05/3.95e-05|3.59e-05/3.59e-05|9.18e-06/9.18e-06|3.59e-05/3.59e-05|9.19e-06/9.19e-06
  half |3.59e-05/3.59e-05|1.99e-05/1.99e-05|1.81e-05/1.81e-05|4.74e-06/4.74e-06|1.81e-05/1.81e-05|4.74e-06/4.75e-06
  first|3.59e-05/3.59e-05|2.04e-07/2.04e-07|2.04e-07/2.04e-07|2.13e-07/2.13e-07|2.65e-07/2.66e-07|2.82e-07/2.82e-07
0x10000|
  zero |9.52e-03/1.07e-02|1.14e-02/1.17e-02|1.94e-02/2.04e-02|3.43e-03/3.52e-03|9.59e-03/1.07e-02|3.10e-03/3.17e-03
  last |9.57e-03/1.07e-02|1.14e-02/1.17e-02|9.73e-03/1.08e-02|3.04e-03/3.13e-03|9.57e-03/1.05e-02|3.11e-03/3.22e-03
  half |9.54e-03/1.06e-02|5.06e-03/5.13e-03|4.69e-03/4.76e-03|1.17e-03/1.17e-03|4.60e-03/4.65e-03|1.18e-03/1.18e-03
  first|9.55e-03/1.07e-02|2.28e-06/2.29e-06|2.26e-06/2.27e-06|2.28e-06/2.29e-06|2.34e-06/2.35e-06|2.36e-06/2.36e-06
cc -m64 -g -O3 -W -Wall -Wextra  -o test64 test.c repe.S -lrt
./test64
       |          bit_or |      use_memcmp |     check_bytes |   check_aligned |      repe_scasb |       repe_scas
-------+-----------------+-----------------+-----------------+-----------------+-----------------+-----------------
0x7+4  |
  zero |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.17e-07/1.17e-07|1.26e-07/1.26e-07|1.52e-07/1.52e-07|2.57e-07/2.67e-07
  last |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.04e-07/1.17e-07|1.09e-07/1.09e-07|1.52e-07/1.52e-07|1.70e-07/1.70e-07
  half |9.14e-08/9.14e-08|1.35e-07/1.35e-07|7.83e-08/7.83e-08|5.66e-08/5.66e-08|1.26e-07/1.26e-07|7.83e-08/7.83e-08
  first|9.14e-08/9.14e-08|4.79e-08/4.79e-08|5.23e-08/5.23e-08|5.66e-08/5.66e-08|1.00e-07/1.00e-07|7.83e-08/7.83e-08
0x7+2  |
  zero |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.17e-07/1.17e-07|1.26e-07/1.26e-07|1.52e-07/1.52e-07|2.30e-07/2.57e-07
  last |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.04e-07/1.04e-07|1.09e-07/1.09e-07|1.52e-07/1.52e-07|2.22e-07/2.22e-07
  half |9.14e-08/9.14e-08|1.35e-07/1.35e-07|7.83e-08/7.83e-08|7.83e-08/7.83e-08|1.26e-07/1.26e-07|1.09e-07/1.09e-07
  first|9.14e-08/9.14e-08|4.79e-08/4.79e-08|5.23e-08/5.23e-08|5.66e-08/5.66e-08|1.00e-07/1.00e-07|7.40e-08/7.40e-08
0x7+1  |
  zero |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.17e-07/1.17e-07|1.17e-07/1.17e-07|1.52e-07/1.52e-07|2.30e-07/2.32e-07
  last |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.04e-07/1.04e-07|1.04e-07/1.13e-07|1.52e-07/1.52e-07|1.52e-07/1.52e-07
  half |9.14e-08/9.14e-08|1.35e-07/1.35e-07|7.83e-08/7.83e-08|7.40e-08/7.40e-08|1.26e-07/1.26e-07|1.52e-07/1.52e-07
  first|9.14e-08/9.14e-08|3.92e-08/3.92e-08|4.36e-08/4.36e-08|4.79e-08/4.79e-08|1.00e-07/1.00e-07|7.83e-08/7.83e-08
0x7    |
  zero |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.17e-07/1.17e-07|1.52e-07/1.52e-07|1.52e-07/1.52e-07|2.39e-07/2.65e-07
  last |9.14e-08/9.14e-08|1.65e-07/1.65e-07|1.04e-07/1.04e-07|1.26e-07/1.26e-07|1.52e-07/1.52e-07|1.70e-07/1.70e-07
  half |9.14e-08/9.14e-08|1.35e-07/1.35e-07|7.83e-08/7.83e-08|6.53e-08/6.53e-08|1.26e-07/1.26e-07|8.70e-08/8.70e-08
  first|9.14e-08/9.14e-08|4.79e-08/4.79e-08|5.23e-08/5.23e-08|6.53e-08/6.53e-08|1.00e-07/1.00e-07|8.70e-08/8.70e-08
0x400  |
  zero |9.04e-06/9.04e-06|9.90e-06/9.90e-06|9.03e-06/9.05e-06|2.36e-06/2.36e-06|9.01e-06/9.01e-06|1.25e-06/1.25e-06
  last |9.04e-06/9.04e-06|9.90e-06/9.90e-06|9.03e-06/9.03e-06|2.35e-06/2.35e-06|9.01e-06/9.01e-06|1.23e-06/1.23e-06
  half |9.04e-06/9.04e-06|5.02e-06/5.02e-06|4.59e-06/4.59e-06|1.25e-06/1.25e-06|4.57e-06/4.57e-06|6.84e-07/6.84e-07
  first|9.04e-06/9.04e-06|6.19e-08/7.47e-08|7.91e-08/7.92e-08|7.03e-08/7.05e-08|1.14e-07/1.15e-07|1.27e-07/1.28e-07
0x1000 |
  zero |3.61e-05/3.61e-05|3.93e-05/3.93e-05|3.58e-05/3.58e-05|9.08e-06/9.08e-06|3.58e-05/3.58e-05|4.64e-06/4.64e-06
  last |3.61e-05/3.61e-05|3.93e-05/3.93e-05|3.58e-05/3.58e-05|9.07e-06/9.07e-06|3.58e-05/3.58e-05|4.61e-06/4.61e-06
  half |3.61e-05/3.61e-05|1.97e-05/1.97e-05|1.80e-05/1.80e-05|4.63e-06/4.63e-06|1.80e-05/1.80e-05|2.40e-06/2.40e-06
  first|3.61e-05/3.61e-05|1.04e-07/1.17e-07|1.21e-07/1.21e-07|1.26e-07/1.26e-07|1.58e-07/1.58e-07|1.71e-07/1.71e-07
0x10000|
  zero |1.08e-02/1.09e-02|1.03e-02/1.04e-02|9.38e-03/9.50e-03|2.41e-03/2.49e-03|9.33e-03/9.50e-03|1.67e-03/1.73e-03
  last |1.08e-02/1.09e-02|1.03e-02/1.04e-02|9.38e-03/9.49e-03|2.44e-03/2.55e-03|9.33e-03/9.47e-03|1.62e-03/1.67e-03
  half |1.08e-02/1.10e-02|5.05e-03/5.12e-03|4.61e-03/4.69e-03|1.16e-03/1.16e-03|4.59e-03/4.66e-03|6.63e-04/6.65e-04
  first|1.08e-02/1.09e-02|8.70e-07/8.80e-07|8.70e-07/8.80e-07|8.90e-07/9.00e-07|9.60e-07/9.60e-07|9.70e-07/9.80e-07
$ uname -srvmp
Linux 2.6.32-gentoo #1 SMP Sun Dec 6 16:24:50 EST 2009 x86_64 AMD Phenom(tm) 9600 Quad-Core Processor

如您所见,

  • 对于简短数据,简单就更好了
  • memcmp实际上非常擅长爬行内存(至少采用GCC 4.4.2适用的优化)
  • x86的字符串内在函数有点帮助
  • 长数据的最大收益来自于更大的进步 - 尽可能避免逐字节访问。

答案 12 :(得分:0)

另一种C ++解决方案:

bool all_zero( const char * buf, size_t len )
{
    return (buf == std::search_n( buf, buf+len, len, 0 ) );
}

search_n返回第一次出现的一系列“len”连续出现的值(此处为0)或返回“end”。在这个特定的应用程序中,它显然要么返回序列的开头,要么返回结束。

这样做的好处是我也可以将它应用于一个int,double等数组,这些数组能够逐字检查。 (显然,使all_zero成为一个模板)。

答案 13 :(得分:-1)

您想要的功能称为memset

这样称呼:

memset(pMem, '\0', iMemSize);