我的意思是,我malloc一段内存,也许1k可能是20bytes ..
假设指针是pMem
如何知道所提及的内容pMem
全部为Zero
或\0
。我知道memcmp
但第二个参数应该是另一个内存地址......
感谢名单
答案 0 :(得分:20)
但是如果你确实想检查一个内存区域是否全为零,你可以将它与自身进行比较,但是将其移动一个。
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
。如果您要将内存块设置为全零,请使用memset
或std::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的样本。 我测试了以下内容:
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
如您所见,
答案 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)