【问题标题】:Compare two 64 bit variables on 32 bit microcontroller比较 32 位微控制器上的两个 64 位变量
【发布时间】:2019-02-25 11:58:18
【问题描述】:

我有以下问题:我有两个 64 位变量,必须尽快比较它们,我的微控制器只有 32 位。

我的想法是有必要将64位变量分成两个32位变量,像这样

uint64_t var = 0xAAFFFFFFABCDELL;
hiPart = (uint32_t)((var & 0xFFFFFFFF00000000LL) >> 32);
loPart = (uint32_t)(var & 0xFFFFFFFFLL);

然后比较 hiParts 和 loParts,但我确信这种方法很慢并且有更好的解决方案

【问题讨论】:

  • 我认为没有完全不同的概念可以做到这一点,因为如果它们相等,您仍然需要比较每一位。但是,您可以通过先比较高部分来改进比较。如果高部分不同,则低部分不再重要。
  • 您的编译器允许按位与和移位 64 位值,但不允许 == 或其他比较运算符?
  • 如果编译器支持uint64_t,那么编译器可以比较uint64_t类型的两个变量。您只需if (var1 == var2)
  • 以防编译器无论如何都不会删除它,不需要在高位进行按位与。右移无符号值会清除高位。无论如何,投射到 32 位也会丢弃它们。

标签: c int 32-bit


【解决方案1】:

如果您与工会合作,则无需任何额外计算即可比较 Hi 和 Lo Part:

typedef union
{
    struct
    {    
        uint32_t   loPart;
        uint32_t   hiPart;
    };
    uint64_t       complete;
}uint64T;

uint64T var.complete = 0xAAFFFFFFABCDEULL;

【讨论】:

  • 虽然这仅适用于比较,但请注意访问 "lo""hi" 部分取决于字节序。
  • 当然可以。放置两个 64 位值的比较会很快。
【解决方案2】:

第一条规则应该是:编写你的程序,以便人类可以阅读

当有疑问时,不要假设任何事情,而是衡量它。让我们看看,godbolt 给了我们什么。

#include <stdint.h>
#include <stdbool.h>

bool foo(uint64_t a, uint64_t b) {
    return a == b;
}

bool foo2(uint64_t a, uint64_t b) {

    uint32_t ahiPart = (uint32_t)((a & 0xFFFFFFFF00000000ULL) >> 32);
    uint32_t aloPart = (uint32_t)(a & 0xFFFFFFFFULL);
    uint32_t bhiPart = (uint32_t)((b & 0xFFFFFFFF00000000ULL) >> 32);
    uint32_t bloPart = (uint32_t)(b & 0xFFFFFFFFULL);

    return ahiPart == bhiPart && aloPart == bloPart;
}

 

foo:
        eor     r1, r1, r3
        eor     r0, r0, r2
        orr     r0, r0, r1
        rsbs    r1, r0, #0
        adc     r0, r0, r1
        bx      lr

foo2:
        eor     r1, r1, r3
        eor     r0, r0, r2
        orr     r0, r0, r1
        rsbs    r1, r0, #0
        adc     r0, r0, r1
        bx      lr

如您所见,它们生成完全相同的汇编代码,但您决定哪一个更不容易出错且更易于阅读?

【讨论】:

    【解决方案3】:

    最快的方法是让编译器来做。大多数编译器在微优化方面都比人类好得多。

    uint64_t var = …, other_var = …;
    if (var == other_var) …
    

    没有很多方法可以解决它。在后台,编译器会安排将每个变量的高 32 位和低 32 位加载到寄存器中,并比较包含高 32 位的两个寄存器和包含低 32 位的两个寄存器。汇编代码可能如下所示:

    load 32 bits from &var into r0
    load 32 bits from &other_var into r1
    if r0 != r1: goto different
    load 32 bits from &var + 4 into r2
    load 32 bits from &other_var + 4 into r3
    if r2 != r3: goto different
    // code for if-equal
    different:
    // code for if-not-equal
    

    以下是编译器比你更了解的一些事情:

    • 根据周围代码的需要使用哪些寄存器。
    • 是重复使用相同的寄存器来比较上下部分,还是使用不同的寄存器。
    • 是先处理一个部分然后再处理另一个(如上所述),还是先加载一个变量然后再加载另一个。最佳顺序取决于寄存器压力以及特定处理器模型的内存访问时间和流水线。

    【讨论】:

      【解决方案4】:

      几年前有一段时间,您需要做一些技巧才能比编译器更聪明。但在 99.999% 的情况下,编译器会比你更聪明。

      而且你的变量是无符号的。所以使用ULL 而不是LL

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-26
        • 2014-10-17
        • 2011-07-24
        • 1970-01-01
        • 2018-10-25
        • 1970-01-01
        相关资源
        最近更新 更多