Самый быстрый способ убедиться, что область памяти пуста (все NULL)?

Если у меня есть указатель unsigned char *data и я хочу проверить, является ли size_t length данных на этом указателе NULL, какой бы самый быстрый способ это сделать? Другими словами, какой самый быстрый способ убедиться, что область памяти пуста?

Я внедряю в iOS, поэтому вы можете предположить, что рамки iOS доступны, если это помогает. С другой стороны, простые подходы C ( memcmp и т. П.) Также в порядке.

Заметьте, я не пытаюсь очистить память, а попытаюсь подтвердить, что она уже понятна (я пытаюсь выяснить, есть ли вообще что-то в некоторых растровых данных, если это помогает). Например, я думаю, что следующее будет работать, хотя я еще не пробовал:

 - BOOL data:(unsigned char *)data isNullToLength:(size_t)length { unsigned char tester[length] = {}; memset(tester, 0, length); if (memcmp(tester, data, length) != 0) { return NO; } return YES; } 

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

ОБНОВЛЕНИЕ: некоторые тесты

Спасибо всем за отличные ответы ниже. Я решил создать тестовое приложение, чтобы посмотреть, как они выполняются, ответы меня удивили, поэтому я решил поделиться ими. Сначала я покажу вам версию алгоритмов, которые я использовал (в некоторых случаях они немного отличаются от предложенных), а затем я поделился некоторыми результатами с поля.

Тесты

Сначала я создал несколько выборочных данных:

  size_t length = 1024 * 768; unsigned char *data = (unsigned char *)calloc(sizeof(unsigned char), (unsigned long)length); int i; int count; long check; int loop = 5000; 

Каждый тест состоял из циклов loop . Во время цикла некоторые случайные данные были добавлены и удалены из потока байтов data . Обратите внимание, что в половине случаев фактически не было добавлено данных, поэтому в половине случаев тест не должен находить ненулевые данные. Обратите внимание, что вызов testZeros является заполнителем для вызовов в тестовые процедуры ниже. Таймер запускался до цикла и останавливался после цикла.

  count = 0; for (i=0; i<loop; i++) { int r = random() % length; if (random() % 2) { data[r] = 1; } if (! testZeros(data, length)) { count++; } data[r] = 0; } 

Тест A: nullToLength. Это была более или менее моя первоначальная формулировка выше, немного отлажена и упрощена.

 - (BOOL)data:(void *)data isNullToLength:(size_t)length { void *tester = (void *)calloc(sizeof(void), (unsigned long)length); int test = memcmp(tester, data, length); free(tester); return (! test); } 

Тест B: allZero. Предложение Карротмана.

 BOOL allZero (unsigned char *data, size_t length) { bool allZero = true; for (int i = 0; i < length; i++){ if (*data++){ allZero = false; break; } } return allZero; } 

Тест C: is_all_zero. Предлагается Лундином.

 BOOL is_all_zero (unsigned char *data, size_t length) { BOOL result = TRUE; unsigned char* end = data + length; unsigned char* i; for(i=data; i<end; i++) { if(*i > 0) { result = FALSE; break; } } return result; } 

Тест D: sumArray. Это главный ответ от почти дублирующего вопроса , предложенного владром.

 BOOL sumArray (unsigned char *data, size_t length) { int sum = 0; for (int i = 0; i < length; ++i) { sum |= data[i]; } return (sum == 0); } 

Тест E: lulz. Предлагается Стивом Джессопом.

 BOOL lulz (unsigned char *data, size_t length) { if (length == 0) return 1; if (*data) return 0; return memcmp(data, data+1, length-1) == 0; } 

Тест F: NSData. Это тест с использованием объекта NSData, который я обнаружил в SDK iOS, работая над всеми этими. Оказывается, Apple действительно имеет представление о том, как сравнивать потоки байтов, которые предназначены для аппаратного независимого.

 - (BOOL)nsdTestData: (NSData *)nsdData length: (NSUInteger)length { void *tester = (void *)calloc(sizeof(void), (unsigned long)length); NSData *nsdTester = [NSData dataWithBytesNoCopy:tester length:(NSUInteger)length freeWhenDone:NO]; int test = [nsdData isEqualToData:nsdTester]; free(tester); return (test); } 

Результаты

Итак, как эти сравнения сравнивались? Вот два набора данных, каждый из которых представляет 5000 циклов через проверку. Сначала я пробовал это на симуляторе iPhone, работающем на относительно старом iMac, и я попробовал это на iPad первого поколения.

На iPhone 4.3 Симулятор работает на iMac:

 // Test A, nullToLength: 0.727 seconds // Test F, NSData: 0.727 // Test E, lulz: 0.735 // Test C, is_all_zero: 7.340 // Test B, allZero: 8.736 // Test D, sumArray: 13.995 

На первом поколении iPad:

 // Test A, nullToLength: 21.770 seconds // Test F, NSData: 22.184 // Test E, lulz: 26.036 // Test C, is_all_zero: 54.747 // Test B, allZero: 63.185 // Test D, sumArray: 84.014 

Это всего лишь два образца, я много раз тестировал тест с небольшими изменениями. Порядок исполнения всегда был один и тот же: A & F очень близко, E только позади, C, B и D. Я бы сказал, что A, F и E являются виртуальными связями, на iOS я бы предпочел F, потому что это использует защиту Apple от проблем смены процессора, но A & E очень близки. Подход memcmp явно выигрывает за простой подход к петле, почти в десять раз быстрее в симуляторе и в два раза быстрее на самом устройстве. Как ни странно, D, выигрышный ответ из другого потока, выполненный очень плохо в этом тесте, вероятно, потому, что он не выходит из цикла, когда он попадает в первую разницу.

6 Solutions collect form web for “Самый быстрый способ убедиться, что область памяти пуста (все NULL)?”

Не уверен, что это лучший, но я, вероятно, сделаю что-то вроде этого:

 bool allZero = true; for (int i = 0; i < size_t; i++){ if (*data++){ //Roll back so data points to the non-zero char data--; //Do whatever is needed if it isn't zero. allZero = false; break; } } 

Если вы только что выделили эту память, вы всегда можете вызывать calloc, а не malloc (calloc требует, чтобы все данные были обнулены). (Редактируйте: читайте свой комментарий к первому сообщению, вам это действительно не нужно. Я просто оставлю его на всякий случай)

Я думаю, вы должны сделать это с явным циклом, но только для lulz:

 if (length == 0) return 1; if (*pdata) return 0; return memcmp(pdata, pdata+1, length-1) == 0; 

В отличие от memcpy , memcmp не требует, чтобы два раздела данных не перекрывались.

Однако это может быть медленнее, чем цикл, потому что несогласованность указателей на вход означает, что, возможно, реализация memcmp , а также сравнивает память с памятью, а не память с константой. Достаточно легко профилировать его и узнать.

Если вы сами распределяете память, я бы предложил использовать функцию calloc() . Это точно так же, как malloc() , за исключением того, что он сначала вытесняет буфер. Это то, что используется для выделения памяти для объектов Objective-C и является причиной того, что все ivars по умолчанию равны 0.

С другой стороны, если это статически объявленный буфер или буфер, который вы не выделяете самостоятельно, memset() – это простой способ сделать это.

Логика, чтобы получить значение, проверить его и установить, будет, по крайней мере, так же дорого, как его установка. Вы хотите, чтобы он был нулевым, поэтому просто установите для него значение null, используя memset ().

Это было бы предпочтительным способом сделать это в C:

 BOOL is_all_zero (const unsigned char* data, size_t length) { BOOL result = TRUE; const unsigned char* end = data + length; const unsigned char* i; for(i=data; i<end; i++) { if(*i > 0) { result = FALSE; break; } } return result; } 

(Хотя обратите внимание, что строго и формально говоря, ячейка памяти, содержащая NULL-указатель, необязательно должна быть 0, если нулевой указатель-указатель приводит к нулевому значению, а приведение от нуля к указателю приводит к указателю NULL На практике это не имеет значения, поскольку все известные компиляторы используют 0 или (void *) 0 для NULL.)

Обратите внимание на редактирование исходного вопроса выше. Я сделал несколько тестов, и ясно, что подход memcmp или использование объекта NSData Apple и его метод isEqualToData: – лучшие подходы к скорости. Простые циклы яснее для меня, но медленнее на устройстве.

Interesting Posts

По требованию ресурсов в iOS 9 – как узнать точное местоположение загруженных ресурсов?

Создавать более гладкие края или иным образом фиксировать зубчатые края на коробке в SCNView?

AVAudioPlayer не играет в фоновом режиме, когда iPhone заблокирован

Удалить границу UISearchBar в iOS7

Objective-c + RestKit – Подождите ответа до следующего шага

sqlite3_prepare_v2! = SQLITE_OK

Как получить неуправляемую версию объекта Realm

Проблемы с получением элементов по имени из UIAElementArray в UIAutomation

Как проверить SKPaymentTransactionStateDeferred?

iphone sdk: ограничения локальных уведомлений

Как отладить его в мобильном сафари и симуляторе ios?

Получить список установленных приложений на iPhone

Поппер не указывает на кнопку

Как изменить размер изображения в соответствии с ячейкой UITableView?

Как получить доступ к макроу, определенному в моем pch, из библиотеки cocoapods?

PhoneC: Разработка iOS проста с помощью XCode, Swift3, UITableView, cocatouch, давайте создадим приложения для iPhone, iPad и Macbook.