GCC 和 Clang 会优化逐字段结构复制吗?

Ale*_*nov 5 c c++ gcc struct clang

例如给定

typedef struct A {
    int a;
    int b;
    int c;
} A;

typedef struct B {
    int d;
    int e;
    int f;
} B;

void f(B& b1, A& a2) {
    b1.d = a2.a;
    b1.e = a2.b;
    b1.f = a2.c;
}
Run Code Online (Sandbox Code Playgroud)

f可以用 a 替换memcpy(特别是如果结构有更多字段)。

  1. 两个版本都会产生等效的代码吗?

  2. 如果我们复制到的结构的字段少于A?IE

    typedef struct C {
        int g;
        int h;
    } C;
    
    void h(C& c1, A& a2) {
        c1.g = a2.a;
        c1.h = a2.b;
    }
    
    Run Code Online (Sandbox Code Playgroud)

我很感兴趣,因为我正在生成包含这样的结构副本的代码,通常会更改字段的顺序,我想知道是否应该对这些情况进行特殊处理。

包含 C 标记是因为我希望 C 中的行为是相同的(模指针而不是引用)。

Ric*_*ith 3

您的测试用例没有加载和存储足够的内存,因此值得转换为 memcpy。使用两倍的成员:

typedef struct A { int a, b, c, p, q, r; } A;
typedef struct B { int d, e, f, s, t, u; } B;
void f(B& b1, A& a2) {
  b1.d = a2.a;
  b1.e = a2.b;
  b1.f = a2.c;
  b1.s = a2.p;
  b1.t = a2.q;
  b1.u = a2.r;
}
Run Code Online (Sandbox Code Playgroud)

... LLVM 将代码优化为:

f(B&, A&):                             # @f(B&, A&)
        movups  (%rsi), %xmm0
        movups  %xmm0, (%rdi)
        movl    16(%rsi), %eax
        movl    %eax, 16(%rdi)
        movl    20(%rsi), %eax
        movl    %eax, 20(%rdi)
        retq
Run Code Online (Sandbox Code Playgroud)

...使用未对齐的 16 字节加载/存储复制前四个成员。