每n字节复制内存



我有一个uint8_t值数组,我的目标是每3个字节复制到dst数组,但问题是我在dst数组中从4到4个字节迭代,就像下面所示。

src = {1,2,3,4,5,6};
dst = {0,0,0,0,0,0,0,0};
...
dst = {1,2,3,0,4,5,6,0}

现在我使用下面的代码来执行这个任务。

for(int i=0; i<arr_size ; i++)
memcpy(dst + i*4, arr_ptr + i*3, 3);

是否有更快/更有效的方法来做到这一点?

编辑更多上下文:
我有以下结构体,需要填充来自图像数组的数据,其中a将始终初始化为0。

typedef struct {unsigned char r,g,b,a} uchar4;
...
// init dst
...
*dst = (uchar4 *)malloc(height * width * sizeof(uchar4));

通过分配值给uchar4数组做struct.variable = value,需要很多时间,这让我认为它会更快地从图像数组复制值,存储uint8_t值,到uchar4数组,因为uchar和uint8占用1个字节的内存。通过这种方式,structs数组被初始化为0,并且每隔3个字节从扁平图像中粘贴每4个字节到uchar arr中。

Edit2:代码修改

有很多方法可以尝试和优化你的转换循环。正如0___________所建议的那样,对于大小大小的块,您应该考虑使用memcpy,因为大多数优化器将为目标平台生成非常有效的代码,而不是手工编写幼稚的替代方案。

下面是一个比较3种方法的快速基准测试:

  • 显式复制3字节,指针递增。
  • 使用memcpy复制

可以添加其他方法,例如尝试利用SIMD指令,这应该以牺牲可移植性为代价提供显著的性能改进。

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
typedef struct rgb {
uint8_t r, g, b;
} rgb;
typedef struct rgba {
uint8_t r, g, b, a;
} rgba;
void copy3to4_simple(void *to, const void *from, size_t count) {
const uint8_t *src = from;
uint8_t *dst = to;
uint8_t *end = dst + count * 4;
while (dst < end) {
dst[0] = src[0];
dst[1] = src[1];
dst[3] = src[2];
dst += 4;
src += 3;
}
}
void copy3to4_memcpy(void *to, const void *from, size_t count) {
const uint8_t *src = from;
uint8_t *dst = to;
for (size_t i = 0; i < count; i++) {
memcpy(dst + i * 4, src + i * 3, 3);
}
}
int main() {
int width = 1920, height = 1080;
rgb *src = calloc(sizeof(*src), width * height);
rgba *dst = calloc(sizeof(*dst), width * height);
const char *name[10];
clock_t c[10];
int n = 0;
#define RUNS  100
name[n] = "simple";
for (int i = 0; i < RUNS + 10; i++) {
if (i == 10)
c[n] = -clock();
copy3to4_simple(dst, src, width * height);
}
c[n++] += clock();
name[n] = "memcpy";
for (int i = 0; i < RUNS + 10; i++) {
if (i == 10)
c[n] = -clock();
copy3to4_memcpy(dst, src, width * height);
}
c[n++] += clock();
for (int i = 0; i < n; i++) {
printf("%s: %.3f msecn", name[i], c[i] * 1000. / CLOCKS_PER_SEC / RUNS);
}
free(src);
free(dst);
return 0;
}

在我的旧Macbook上运行这个,我得到这个:

simple: 2.478 msec
memcpy: 1.840 msec

memcpysimple高25%,但在不同的架构上可能会得到不同的结果。

我假设arr_size是要复制的三元组的数目。

for(size_t i=0; i<arr_size ; i++)
memcpy(dst + i*3, src + i*4, 3);

是错误的,它必须是

for(size_t i=0; i<arr_size ; i++)
memcpy(dst + i*4, src + i*3, 3);

现在是上下文

typedef struct {unsigned char r,g,b,a} uchar4;

不能保证编译器不会添加任何填充。任何指针双关语都可能无法正常工作。添加静态断言来检查结构的大小是否为4,如果不使用,则需要使用一些编译器扩展来打包结构。

效率:这很难判断,但从这里的答案中可以看出,memcpy版本很可能是最有效的。

https://godbolt.org/z/E4s8sa

我试图删除一个内存访问,写得非常糟糕(它调用UBs!但它可以在X86和Cortex-M3及更新版本上运行)。这样做只是出于好奇:(警告!!图形编程内容!!不适合所有观众)https://godbolt.org/z/Pefc6T

根本不需要memcpy。仅使用指针算术,您就可以执行以下操作:

uint8_t *src = some_values;
uint8_t *end = src + some_values_size;
uint8_t *dst = some_buffer;
for (; src < end; src += 3, dst += 4) {
dst[0] = src[0];
dst[1] = src[1];
dst[2] = src[2];
}
在上面的示例中,您可以将代码定义为宏,并将其用于不同的数据类型。memcpy想知道它需要复制多少字节,因此你需要一个类型。

注意:代码假设数组src的长度是3的倍数,数组dst的长度等于:(length(src) / 3) * 4.

相关内容

  • 没有找到相关文章

最新更新