我正在研究嵌入式系统应用程序。我想从源复制到目标,跳过常量字节数。例如:source[6] = {0,1,2,3,4,5}
我希望目标为{0,2,4}跳过一个字节。遗憾的是memcpy
无法满足我的要求。我怎样才能在C' C'不使用循环,因为我有大量数据要处理和使用循环体验时间开销。
我目前的实现是这样的,需要5-6毫秒才能复制1500字节:
unsigned int len_actual = 1500;
/* Fill in the SPI DMA buffer. */
while (len_actual-- != 0)
{
*(tgt_handle->spi_tx_buff ++) = ((*write_irp->buffer ++)) | (2 << 16) | DSPI_PUSHR_CONT;
}
答案 0 :(得分:0)
你可以写一个&#34;樱桃选择器&#34;功能
void * memcpk(void * destination, const void * source,
size_t num, size_t size
int (*test)(const void * item));
最多复制num
&#34;对象&#34;,每个对象的大小为size
source
到destination
。仅复制满足测试的对象。
然后用
int oddp(const void * intptr) { return (*((int *)intptr))%2; }
int evenp(const void * intptr) { return !oddp(intptr); }
你可以做到
int destination[6];
memcpk(destination, source, 6, sizeof(int), evenp);
答案 1 :(得分:0)
几乎所有的CPU都有缓存;这意味着(例如)当您修改一个字节时,CPU从RAM中获取整个缓存行,修改缓存中的字节,然后将整个缓存行写回RAM。通过跳过小块,可以增加开销(更多关于CPU的说明)并且不会减少缓存和RAM之间传输的数据量。
此外,通常memcpy()
已经过优化,可以复制较大的作品。例如,如果复制一个字节数组但CPU能够一次复制32位(4个字节),则memcpy()
可能会将大部分复制作为每次迭代4个字节的循环进行(减少读写次数,减少循环迭代次数。)
换句话说;由于多种原因,避免复制特定字节的代码会使其明显慢于mempcy()
。
为避免这种情况,您确实希望将需要复制的数据与不包含的数据分开 - 例如把所有不需要复制的东西放在数组的末尾,只复制数组的第一部分(这样它就会保留&#34;复制一个连续的字节区域&#34;)。
如果你不能这样做,下一个考虑的选择就是掩盖。例如,如果你有一个字节数组,其中某些字节不应被复制,那么你也有一个&#34;掩码字节数组&#34;并在循环中执行dest[i] = (dest[i] & mask[i]) | (src[i] & ~mask[i]);
之类的操作。这听起来很可怕(而且很可怕),直到你通过操作更大的碎片来优化它 - 例如如果CPU可以复制32位片段,则屏蔽允许您通过假装所有阵列都是uint32_t
的数组来每次迭代完成4个字节。请注意,对于这种技术,更宽更好 - 例如如果CPU支持对256位片段(80x86上的AVX)的操作,则每次循环迭代可以执行32个字节。如果您可以保证大小和对齐,也会有所帮助(例如,如果CPU一次可以运行32位/ 4字节,请确保数组的大小始终是4个字节的倍数,并且数组始终是4字节对齐;即使它意味着在末尾添加未使用的填充。)
另请注意,根据实际的CPU,可能会在指令集中提供特殊支持。例如,现代80x86 CPU(支持SSE2)具有maskmovdqu
指令,专门用于有选择地写入一些字节而不是其他字节。在这种情况下,你需要诉诸于内在的或内联组装,因为&#34;纯粹的C&#34;不支持这种类型的东西(除了按位运算符)。
答案 2 :(得分:0)
忽略了你的速度要求: 您可以尝试找到一种解决问题而无需复制的方法。
这里有一些想法:
如果要迭代可以定义的destination
数组
一种&#34;挑剔的迭代器&#34; source
的{{1}}前进到您允许的下一个数字:而不是iter++
执行iter = advance_source(iter)
如果要搜索destination
数组,请在搜索bsearch()
的{{1}}周围打一个函数并检查结果。等等。
答案 3 :(得分:0)
根据您的处理器内存宽度和内部寄存器的数量,您可以通过使用移位操作来加快速度。
您需要知道您的处理器是big-endian还是little-endian。
假设您有一个32位处理器和总线,以及至少4个备用寄存器,编译器可以使用这些寄存器进行优化。这意味着您可以在同一个目标字中读取或写入4个字节,读取2个源字。请注意,您正在读取要丢弃的字节。
您还可以通过确保所有内容都是字对齐来提高速度,并忽略缓冲区之间的间隙,因此不必担心奇数字节数。
所以,对于小端:
inline unsigned long CopyEven(unsigned long a, unsigned long b)
{
long c = a & 0xff;
c |= (a>>8) & 0xff00;
c |= (b<<16) & 0xff0000;
c |= (b<<8) &0xff000000;
return c;
}
unsigned long* d = (unsigned long*)dest;
unsigned long* s = (unsigned long*)source;
for (int count =0; count <sourceLenBytes; count+=8)
{
*d = CopyEven(s[0], s[1]);
d++;
s+=2;
}