c - 带有 & 操作的 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;
}}
是通过全局变量还是通过函数参数使其工作?
解决方案
好像你在这里发现了一个真正的编译器错误!
海合会版本:
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 版本都会受到影响,直到这个问题得到修复。
推荐阅读
- swift - 如何将字符串转换为字符数组?
- javascript - 如何在没有 html 的 javascript 中创建有序/编号列表
- jdbc - Salesforce JDBC 连接
- html - Material UI React 应用程序中没有滚动条的全高和全宽
- java - 编写特征属性检查总是假的 Android BluetoothGatt 类
- php - 我如何在braintree GRANT API php中获取付款方式令牌
- identityserver4 - IdentityServer4 .Net 标准还是 .Net 核心?
- angular - 如何在“选择”组件中显示不同的名称?
- google-apps-script - 如何修复返回的错误代码 500 以登录需要 CSRF 令牌的网站
- c++ - Makefile 在 Linux 下工作但在 Windows 下不工作,在子目录中找不到文件