首页 > 解决方案 > 带有 & 操作的 uint64_t 变量

问题描述

我有一个函数在 64 位变量(RFID 标签号)中搜索一系列九个“1”,如果找到,将它们移动到 MSB。我很难理解为什么它不能正常工作。

这是我的变量

uint64_t volatile RFID_data2= 0b1111111110000000000000000000000000000000000000000000000000000000;

我将它作为指向函数的指针发送

test_flag= header_align(&RFID_data2);


uint8_t header_align(uint64_t *data){

uint64_t bit_mask=(uint64_t) 
0b1111111110000000000000000000000000000000000000000000000000000000;


if((*data&bit_mask)==bit_mask){
PORTA ^= (1<<PORTA2);
return 1;
}

这个条件永远不会满足,但是如果我将条件更改为:

if((*data==bit_mask){
PORTA ^= (1<<PORTA2);
return 1;
    }

它似乎运作良好。

更重要的是,我写了另一个条件 - 这是有效的。

if((*data&bit_mask)>(bit_mask-1) && (*data&bit_mask)<(bit_mask+1 )){
    PORTA ^= (1<<PORTA2);
    return 1

正如我所看到的,这是 AND '&' 操作的问题。此外,当我将 RFID_data 更改为 32 位变量时没有任何问题。我正在使用 Attiny441 和 GCC 编译器,Atmel Studio 有没有办法让它在 64 位上工作?

我将函数更改为采用 uint64t(非指针),但问题仍然存在。我还尝试创建全局变量,并删除 volatile 修饰符,但它仍然无法正常工作。使用宏 UINT64_C 也无济于事。看起来像 :

uint64_t RFID_data;// global var

int main(void)
{
  RFID_data=(0xFF80000000000000);// write into global var
 uint64_t RFID_data2=(0xFF80000000000000);
   while(1)
   {
    test_flag=header_align(RFID_data2);// send local variable
   }
}


 uint8_t header_align(uint64_t data){
  uint64_t bit_mask = UINT64_C(0xFF80000000000000);


    if((data&bit_mask)==bit_mask){
     PORTA ^= (1<<PORTA2);//nothink
        return 1;
    }

我还尝试通过全局变量检查 if-condtion:

     if((RFID_data&bit_mask)==bit_mask){
     PORTA ^= (1<<PORTA2);///nothink
        return 1;
    }

在这两种方式中,它都不会返回 1,也不会改变 PORTA2 的状态。

它仅在我在 header_allgin 中创建新的局部变量时才有效,如下所示:

 uint8_t header_align(uint64_t data){
  uint64_t RFID_data3 = UINT64_C(0xFF80000000000000);
  uint64_t bit_mask = UINT64_C(0xFF80000000000000);


    if((RFID_data3&bit_mask)==bit_mask){
     PORTA ^= (1<<PORTA2);// here i can see signal
        return 1;
    }}

是通过全局变量还是通过函数参数使其工作?

标签: cavratmelattiny

解决方案


好像你在这里发现了一个真正的编译器错误!

海合会版本:

avr-gcc (GCC) 4.8.1

(启用 -O1 或 -O2 优化,在 -O0 处似乎不存在问题)

减少测试用例:

#include <stdint.h>


uint8_t volatile tmp;


__attribute__((noinline)) void test_64(uint64_t d64)
{
 if ((d64 & 0xFF800000UL) == 0xFF800000UL){
  tmp ++;
 }
}

__attribute__((noinline)) void test_32(uint32_t d32)
{
 if ((d32 & 0xFF800000UL) == 0xFF800000UL){
  tmp ++;
 }
}


int main(void)
{
 test_64(0);
 test_32(0);

 while(1);
}

关键部分的汇编器输出:

00000228 <test_64>:
 228:   08 95           ret

0000022a <test_32>:
 22a:   66 27           eor r22, r22
 22c:   77 27           eor r23, r23
 22e:   80 78           andi    r24, 0x80   ; 128
 230:   61 15           cp  r22, r1
 232:   71 05           cpc r23, r1
 234:   80 48           sbci    r24, 0x80   ; 128
 236:   9f 4f           sbci    r25, 0xFF   ; 255
 238:   09 f0           breq    .+2         ; 0x23c <test_32+0x12>
 23a:   08 95           ret
 23c:   80 91 00 20     lds r24, 0x2000
 240:   8f 5f           subi    r24, 0xFF   ; 255
 242:   80 93 00 20     sts 0x2000, r24
 246:   08 95           ret

00000248 <main>:
 248:   20 e0           ldi r18, 0x00   ; 0
 24a:   30 e0           ldi r19, 0x00   ; 0
 24c:   40 e0           ldi r20, 0x00   ; 0
 24e:   50 e0           ldi r21, 0x00   ; 0
 250:   60 e0           ldi r22, 0x00   ; 0
 252:   70 e0           ldi r23, 0x00   ; 0
 254:   80 e0           ldi r24, 0x00   ; 0
 256:   90 e0           ldi r25, 0x00   ; 0
 258:   0e 94 14 01     call    0x228   ; 0x228 <test_64>
 25c:   60 e0           ldi r22, 0x00   ; 0
 25e:   70 e0           ldi r23, 0x00   ; 0
 260:   cb 01           movw    r24, r22
 262:   0e 94 15 01     call    0x22a   ; 0x22a <test_32>
 266:   ff cf           rjmp    .-2         ; 0x266 <main+0x1e>

观察

对于 32 位,生成正确的代码。对于 64 位,根本不执行任何比较,代码编译时就好像结果if始终为假一样。本机 GCC 可以正确编译这两个函数。

您应该避免在代码中使用 64 位变量。

该错误现已在 GCC bugtracker 上得到确认,您可以在此处关注它:

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85805

所以在写这篇文章的时候,所有足够现代的 avr-gcc 版本都会受到影响,直到这个问题得到修复。


推荐阅读