我的意思是,我malloc一段内存,也许1k也许20bytes ..假设指针是pMem
我怎么知道内容pMem
是全Zero
或\0
。 我知道memcmp
但第二个参数应该另一个内存地址… thanx
正如其他人已经建议你可能需要memset或calloc 。
但是如果你真的想要检查一个内存区域是否全为零,你可以将它与自身进行比较,但是移位一个。
bool allZero = pMem[0] == '\0' && !memcmp(pMem, pMem + 1, length - 1);
其中长度是你想要为零的字节数。
由于马克的回答引起了一些争议:
#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倍。 看到其他人的结果会很有趣 – 我的所有记忆都被归零了,所以我总是得到最差的时间。
对于较小的块(以及更多块),比较时间不太重要,但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,然后memcmp的16个字节,以避免未对齐的最坏情况,不会加速太多。
如果你正在测试它,然后只在零时使用它,那么请注意你有一个竞争条件,因为@Mark Byers建议的方法没有原子测试/设置操作。 在这种情况下很难得到正确的逻辑。
如果你想把它归零,如果它不是零,那就把它设置为零,因为这样会更快。
C ++解决方案:
bool all_zeroes = (find_if( pMem, pMem+len, bind2nd(greater<unsigned char>(), 0)) == (pMem+len));
正如你所说的, memcmp
将一块内存与另一块进行比较。 如果你已经知道另外一块内存是全零的,那么你可以使用这个参考块来和你的候选块进行比较,看它们是否匹配。
这听起来像你没有另一块内存,但。 你只有一个,你想知道它是否全是零。 标准库不提供这样的功能,但很容易编写自己的:
bool is_all_zero(char const* mem, size_t size) { while (size-- > 0) if (*mem++) return false; return true; }
如果你想分配一个新的内存块,并立即全部为零,那么使用calloc
而不是malloc
。 如果你有一个你想要设置为全零的内存块,那么使用memset
或者std::fill
。
你可以使用calloc,如果你想分配的内存中的所有0
对于大型缓冲区:
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对比0.63 +/- 0.19,对于超过256000字节的10000次重复,首先移除15次重复的统计)
讨论:从我的经验分析C / C ++到汇编,我不希望编译器做这个优化 – 因为它是一个小size
的pessimization,并且这种类型的优化可能性是少之又少。 大约4的因素证实了这个假设 – 就像看拆卸一样。
另外,大多数应用程序的总时间可以忽略不计,高速缓存未命中会更糟糕,并影响两个版本相同。
它的乐趣:
重叠memcmp时钟在1:1.4 ,这是比单字节检查(惊讶我一点)好得多。
请注意,未对齐的读取使得该平台非常依赖。
如果你需要的内存是零,只是memset()
它为零; 检查它是否为零是浪费时间,因为它可能不是,你最终会做更多的工作,检查,然后设置。
然而,如果你真的想有效地检查一个内存区域,看看它是否全为零,你可以对其他已知全部为零的东西进行memcmp()
。 例如,您可以分配一个内存块,然后保留一个指针,以便与其他内存块进行比较。
另一个C ++解决方案比Kirill稍微简单一些。 但是,即使该序列包含非零元素,它也会遍历整个序列。
bool all_zeroes = std::count(pMem, pMem + length, 0) == length;
更多的基准:
粗略地基于Steve Jessop的样本。 我测试了以下内容:
std::find_if
这些都没有任何关于数组的假设,只是接受和处理一个字符数组。
最后,我做了第五个版本,将数组转换为整数,然后对其进行比较。 (这个很明显假定数组的大小可以被sizeof(int)
整除,所以它不是一般的,但是我添加了它来证明使用合理的chunk大小是一个比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位读取可能会表现得更好。
与史蒂夫·杰西奥斯代码搞笑,我发现这个变种
int checkzeros(char *f, char *l) { char a = 0; while (f < l) { a |= *f++; } if (a) { return 0; } return 1; }
要快50%左右(核心循环中没有分支机构)。 所有的错误都是我的。
正如史蒂夫指出的,这个版本有一个好的最坏的情况和一个可怕的最好的情况(因为它们是一样的)。 只有在完全置零的缓冲区是唯一需要快速处理的情况下才能使用它。
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%之内)。
$使时间 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 | 零| 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 最后| 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 半| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 | 0 | 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 最后| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 | 零| 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 最后| 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 半| 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 第一| 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 12月6日16:24:50 EST 2009 x86_64 AMD Phenom(tm)9600四核处理器
如你看到的,
另一个C ++解决方案:
bool all_zero( const char * buf, size_t len ) { return (buf == std::search_n( buf, buf+len, len, 0 ) ); }
search_n返回值为“len”的连续出现序列的第一次出现(这里是0)或返回“结束”。 在这个特定的应用程序中,显然要么返回序列的开始或结束。
这样做的好处是我也可以将它应用于整数,双精度等,这将能够检查逐字。 (显然使all_zero模板来做到这一点)。
The function you want is called memset .
像这样调用它:
memset(pMem, '\0', iMemSize);