[英]How can I know where the segment of memory is all Zero
我的意思是,我的malloc內存段,也許1K也許20字節..假設指針pMem
我怎么能知道內容pMem
refered都是Zero
或\\0
。 我知道memcmp
但第二個參數應該是另一個內存地址... thanx
由於馬克的回答引起了一些爭議:
#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,以避免未對齊的最壞情況,也不會加快它的速度。
如果你正在測試它,然后只在它為0時才使用它,那么請注意你有一個競爭條件,因為@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
。
如果要分配內存中的所有0,可以使用calloc
對於大緩沖區:
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
來說是一種悲觀,並且這種類型的優化可能性很少。 大致為4的因素證實了這一點 - 正如看反匯編一樣。
此外,對於大多數應用程序來說,總時間可以忽略不計,緩存未命中將會更糟,並且會影響兩個版本。
[編輯]為了它的樂趣:
以1:1.4重疊的memcmp時鍾 ,這比單字節檢查要好得多(讓我感到有些驚訝)。
請注意,未對齊的讀取使得強烈依賴於平台。
如果你需要內存為零,只需將memset()
設置為零; 檢查它是否為零是浪費時間,因為它可能不是,你最終會做更多的工作,檢查然后設置。
但是,如果你真的想要有效地檢查一個內存區域以查看它是否全為零,你可以將memcmp()
與其他已知為零的東西進行對比。 例如,您可以分配和歸零一個內存塊,然后保留指向它的指針,以便與其他內存塊進行比較。
另一種C ++解決方案,比Kirill稍微簡單一些。 但是,它的效率稍低,因為即使該序列包含非零元素,它也會遍歷整個序列。
bool all_zeroes = std::count(pMem, pMem + length, 0) == length;
借助Steve Jessops代碼尋找樂趣,我發現了這個變種
int checkzeros(char *f, char *l) {
char a = 0;
while (f < l) {
a |= *f++;
}
if (a) {
return 0;
}
return 1;
}
大約快50%(核心循環中沒有分支)。 所有的錯誤都是我的。
[編輯]:史蒂夫指出,這個版本有一個很好的最壞情況和一個可怕的最佳情況(因為它們是相同的)。 只有在完全歸零的緩沖區是唯一需要快速的情況時才使用它。
更多基准:
大致基於Steve Jessop的樣本。 我測試了以下內容:
std::find_if
這些都沒有對數組作出任何假設,只是接受並處理一組字符。
最后,我制作了第五個版本,它將數組轉換為整數,並對其進行比較。 (這個顯然假設數組的大小可以被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位讀取可能會更好地執行。
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
如你看到的,
另一種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成為一個模板)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.