2012-04-01 1 views
0

Есть ли быстрый способ подсчитать количество последовательных нулевых байтов, начиная с определенного указателя (char *) в C? В настоящее время я использую жесткий цикл, который работает хорошо и достаточно быстро, но строковые функции libc/gcc имеют тенденцию быть еще быстрее.Как считать последовательные нулевые ( 0) байты в C?

Я ищу что-то похожее на strspn, buf strspn (конечно) останавливается в первом нулевом байте и поэтому бесполезно для этой задачи. Я думаю, вы могли бы также сказать, что я ищу обратный номер strlen, который возвращает количество байтов, которые не null.

+5

Если байт NUL не является концом строки, откуда вы знаете, где заканчивается строка? – delnan

+5

Когда это достаточно быстро ... почему бэттер ?! – Anthales

+2

В реализации библиотеки C имеется, вероятно, рукописный ассемблер. Вы можете перейти к ближайшему выровненному указателю и начать сравнивать целые значения. –

ответ

2

Если указатель слова выровнены, вы можете проверить его на zeroness слово в то время.

int zeros(char *p) 
{ 
    int n = 0; 
    if ((int)p & 1) { 
    if (*p) 
     return 0; 
    p++; 
    n++; 
    } 
    if ((int)p & 2) { 
    if (*(short *)p) 
     goto label1; 
    p += 2; 
    n += 2; 
    } 
    if ((int)p & 4) { 
    if (*(long *)p) 
     goto label2; 
    p += 4; 
    n += 4; 
    } 
    while (!*(long long *)p) { 
    p += 8; 
    n += 8; 
    } 
    if (!*(long *)p) { 
    p += 4; 
    n += 4; 
    } 
label2: 
    if (!*(short *)p) { 
    p += 2; 
    n += 2; 
    } 
label1: 
    if (!*p) 
    n++; 
    return n; 
} 
+0

Приятная идея, но мне неловко предположим, что int имеет длину 4 символа и т. д. –

+0

'int' не гарантированно будет достаточно большим, чтобы удерживать значение указателя. Используйте '(u) intptr_t' из' stdint.h' или, если недоступно, 'size_t'. –

+0

@KyleJones: вы можете использовать 'sizeof()' для проверки размера шрифта. Вы также можете использовать [compile-time "assert"] (http://www.flipcode.com/archives/Compile-Time_Asserts.shtml), чтобы ваш код не компилировался на платформах, где размер отличается. –

3

Я не знаю, существует ли такой метод, но если вам нужно написать его самостоятельно, вы можете рассмотреть возможность проверки наборов из 4 или 8 байт вместе с использованием (int*) или (long*).

+0

Это хорошая идея, но в конце вы должны измерить. И очень часто самое простое решение обнаруживается быстрее. (Я помню, я был удивлен, что java-компилятор пытается выполнить 8 итераций последовательно, чтобы сохранить приращения, в результате чего jit делает цикл медленнее :-() –

+0

Не существует сильной корреляции между сложностью кода и его эффективностью Размер и сложность - это не то же самое. – Vincent

2

Как насчет этого?

char* start = ... 
char* act = start; 
while (*act++ == 0); 
ptrdiff_t nulls = (act - start) - 1; 

Однако что-то должно гарантировать в то время как остановить, прежде чем он достигнет Недоступные модуля памяти

+1

'ptrdiff_t' или' size_t', но не 'int'. –

+0

Это по существу тупиковая петля, которую я сейчас использую. Спасибо, хотя :) –

2

Существует не более быстрый способ сделать это в переносном, стандартный C.

компилятор Си и встроенные функции стандартной библиотеки может идти быстрее, потому что они не должны быть написаны в переносном, стандарт C - они могут свободно использовать знания, специфичные для реализации.

Конечно, вы можете пройти этот маршрут самостоятельно, но если у вас уже достаточно быстро, то действительно ли это стоит затрат на переносимость и ремонтопригодность?