基本上我正在构建一个位读取器,稍微在缓冲区耗尽之前,我想将数组中剩下的任何内容复制到同一个数组的开头,然后在复制之后将所有内容归零,并填充其余部分来自输入文件中的数据。
我只是出于可移植性的原因尝试使用标准库。
另外,我之前正在对我的位读取器进行剖析,而且仪器表示完成这一切需要花费28毫秒,它应该花费那么长时间吗?
删除了代码
答案 0 :(得分:4)
我建议使用memmove
作为副本。它具有与memcpy
相同的签名和功能,除了在重叠区域之间复制是安全的(这就是您所描述的)。
对于零填充,memset
通常就足够了。例如,在没有使用基础零序列表示空指针的情况下,您需要根据类型使用赋值来自行滚动。
出于这个原因,您可能希望隐藏抽象背后的memmove
和memset
操作,例如:
#include <string.h>
void copy_int(int *destination, int *source, size_t size) {
memmove(destination, source, size * sizeof *source);
}
void zero_int(int *seq, size_t size) {
memset(seq, 0, size * sizeof *seq);
}
int main(void) {
int array[] = { 0, 1, 2, 3, 4, 5 };
size_t index = 2
, size = sizeof array / sizeof *array - index;
copy_int(array, array + index, size);
zero_int(array + size, index);
}
如果将来memmove
或memset
变得不适合使用,那么放入你自己的副本/零循环就很简单了。
至于你的奇怪的探查器结果,我想你可能会使用一些过时的(或严重低频的)实现,或者试图复制巨大的阵列......否则,28毫秒看起来确实很荒谬。尽管如此,您的探查器肯定会确定此memmove
和memset
不是执行实际I / O工作的程序中的重要瓶颈,对吧? I / O肯定是瓶颈,对吗?
如果memmove
+ memset
确实是瓶颈,您可以尝试实现循环数组以避免副本。例如,以下代码尝试在比喻干草堆needle
中找到input_file
...
否则,如果I / O是一个瓶颈,那么可以应用调整来减少这种情况。例如,以下代码使用setvbuf
建议底层实现尝试使用底层缓冲区来读取文件的块,尽管代码使用fgetc
一次读取一个字符。
void find_match(FILE *input_file, char const *needle, size_t needle_size) {
char input_array[needle_size];
size_t sz = fread(input_array, 1, needle_size, input_file);
if (sz != needle_size) {
// No matches possible
return;
}
setvbuf(input_file, NULL, _IOFBF, BUFSIZ);
unsigned long long pos = 0;
for (;;) {
size_t cursor = pos % needle_size;
int tail_compare = memcmp(input_array, needle + needle_size - cursor, cursor),
head_compare = memcmp(input_array + cursor, needle, needle_size - cursor);
if (head_compare == 0 && tail_compare == 0) {
printf("Match found at offset %llu\n", pos);
}
int c = fgetc(input_file);
if (c == EOF) {
break;
}
input_array[cursor] = c;
pos++;
}
}
注意这里不需要memmove
(或归零,FWIW)吗?我们只是操作,好像数组的开头是cursor
,结束于cursor - 1
,我们用模needle_size
换行以确保没有溢出/下溢。然后,在每次插入后,我们只需递增cursor
...