EFC*_*EFC 8 c cocoa objective-c nsdata ios
如果我有一个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;
}
Run Code Online (Sandbox Code Playgroud)
我宁愿不创建一个测试器阵列,因为源数据可能非常大,我宁愿避免为测试分配内存,即使是暂时的.但我可能在那里过于保守.
感谢大家对下面的好评.我决定创建一个测试应用程序,看看它们是如何表现的,答案让我感到惊讶,所以我想我会分享它们.首先,我将向您展示我使用的算法版本(在某些情况下,它们与提议的算法略有不同),然后我将分享该领域的一些结果.
首先,我创建了一些示例数据:
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;
Run Code Online (Sandbox Code Playgroud)
每个测试由循环运行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;
}
Run Code Online (Sandbox Code Playgroud)
测试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);
}
Run Code Online (Sandbox Code Playgroud)
测试B:allZero.Carrotman提出的建议.
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;
}
Run Code Online (Sandbox Code Playgroud)
测试C:is_all_zero.Lundin提出的建议.
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;
}
Run Code Online (Sandbox Code Playgroud)
测试D:sumArray.这是由vladr提出的几乎重复的问题的最佳答案.
BOOL sumArray (unsigned char *data, size_t length) {
int sum = 0;
for (int i = 0; i < length; ++i) {
sum |= data[i];
}
return (sum == 0);
}
Run Code Online (Sandbox Code Playgroud)
测试E:lulz.由Steve Jessop提出.
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;
}
Run Code Online (Sandbox Code Playgroud)
测试F:NSData.这是一个使用我在iOS SDK中发现的NSData对象的测试,同时处理所有这些.事实证明,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);
}
Run Code Online (Sandbox Code Playgroud)
那么这些方法是如何比较的?这里有两组数据,每组代表5000个循环检查.首先,我在相对较旧的iMac上运行的iPhone模拟器上尝试了这个,然后我尝试在第一代iPad上运行.
在iMac上运行的iPhone 4.3模拟器上:
// 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
Run Code Online (Sandbox Code Playgroud)
在第一代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
Run Code Online (Sandbox Code Playgroud)
这些只是两个样本,我进行了多次测试,结果略有不同.性能的顺序总是一样的:A&F非常接近,E就在后面,C,B和D.我会说A,F和E是虚拟联系,在iOS上我更喜欢F因为它利用Apple对处理器更改问题的保护,但A&E非常接近.memcmp方法显然胜过简单的循环方法,在模拟器中接近十倍,在设备本身上快两倍.奇怪的是,D,来自另一个线程的获胜答案在这个测试中表现得非常糟糕,可能是因为当它碰到第一个差异时它不会突破循环.
不确定这是否是最好的,但我可能会这样做:
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;
}
}
Run Code Online (Sandbox Code Playgroud)
如果您刚刚分配了该内存,则始终可以调用 calloc 而不是 malloc(calloc 要求所有数据都清零)。(编辑:阅读您对第一篇文章的评论,您实际上并不需要这个。我将保留它以防万一)
| 归档时间: |
|
| 查看次数: |
1112 次 |
| 最近记录: |