如何将4个字节的char缓冲区复制为long

时间:2017-11-19 20:13:15

标签: c memory

以下是我被问到的面试问题:

您有以下代码:

长数; char buff [50];

如果buff与地址0对齐,则num获得前4个字节的buff的最有效方法是什么; 如果我们想在一个特定的地方获得buff的值k(buff [k])我们将如何做呢?

是否与内存对齐有关?

此致 罗恩

1 个答案:

答案 0 :(得分:4)

首先,要了解该问题旨在询问超出C标准规定的特征。 C标准没有对效率提出要求,因此任何询问效率的问题都必然要求C实现,而不是C标准。面试官并没有探究你对C本身的了解;他们正在探索您对现代硬件,编译器等的了解。

xvan的答案所述,您可以使用*num = * (long *) buff;。如果在问题中隐含一些假设,这可以。为了使其可靠地运作:

  1. long不得有任何陷阱表示,或者我们必须知道正在复制的数据不是陷阱表示。

  2. long必须是四个字节。

  3. 编译器必须容忍别名。也就是说,它不能假设,因为buff的元素是char,我们不会通过指向long的指针来访问它们。

  4. buff必须按照问题中的说明进行四字节对齐,否则目标硬件必须支持未对齐的加载。

  5. 这些特性在C实现中并不罕见,特别是在编译期间选择了相应的选项。这段代码的结果很可能是一个双指令序列,它将4个字节从存储器加载到寄存器,并存储从寄存器到存储器的4个字节。这就是我认为面试官正在测试你的知识。

    然而,这不是一个很好的解决方案。正如评论中提到的Ilja Everilä一样,您只需撰写memcpy(&num, buff, sizeof num);即可。这是复制字节的正确C标准方法,一个好的编译器会优化它。例如,我刚刚在macOS 10.12.6上使用Apple LLVM 8.1.0编译了这个源代码,其中包含“-O3 -std = c11 -S”(请求优化的开关,使用2011 C标准和汇编代码输出):

    #include <stdint.h>
    #include <string.h>
    
    void foo(uint32_t *L, char *A)
    {
        memcpy(L, A, sizeof *L);
    }
    

    并且生成的例程在通常的例程入口和出口代码之间包含这些指令:

    movl    (%rsi), %eax
    movl    %eax, (%rdi)
    

    因此,编译器已将memcpy调用优化为加载指令和存储指令。即使编译器不知道buff的对齐方式,也是如此。它显然“相信”未对齐的加载和存储在目标体系结构上表现得相当好,因此它选择直接使用加载和存储指令实现memcpy,而不是显式调用库例程并循环复制四个单独的字节。

    如果编译器没有像这样立即优化memcpy调用,可能需要一些帮助。例如,如果编译器不知道buff是四字节对齐的,并且目标硬件没有很好地(或者根本)执行未对齐的四字节加载,那么编译器将不会对此进行优化{{1进入一个加载 - 存储对。在这种情况下,一些编译器具有语言扩展,可以让您告诉它们指针超过正常对齐,例如GCC的__builtin_assume_aligned()M.M.提及。例如,Apple LLVM,我可以这样做:

    memcpy

    typedef char AlignedBuffer[50] __attribute__((__aligned__(4))); void foo(uint32_t *L, AlignedBuffer *A) { *L = * (long *) A; } 告诉编译器typedef类型始终是四字节对齐的,至少是这样。当然,这是C语言的扩展,并非所有编译器都可用。 (另外,在执行此操作时,我必须确保使用通过指向其他类型的指针来支持别名的编译器选项。)

    鉴于此编译器已经知道如何优化这种情况,尝试用指针转换来超越它是没有意义的。但是,在其他情况下与其他编译器一起工作时,可能需要使用指针转换来获得所需的性能。但是需要知道这是依赖于实现的,并且代码应该被记录为这样,以便其他人知道它不能在不解决这些问题的情况下移植到其他C实现。

    关于后续问题,可以写AlignedBuffer。这个后续问题的重点可能是探讨您对硬件对齐要求的了解。在许多系统上,尝试从非四字节对齐的地址加载四字节数据会导致异常。因此,当*num = * (long *) (buff + k);不是4的倍数时,此赋值语句可能会在此类硬件上失败。 (另外,我们应该注意k必须使所有要加载的字节都在k之内,或者知道是可以访问的。)面试官可能希望你展示这些知识。

    通常在这样的面试问题中,面试官不一定需要一个正确的答案。大多数情况下,他们希望看到你了解这些问题,对它们有一定的了解,并对可能的解决方法有一些了解。