2010-12-09 84 views
3

我想访问硬件寄存器(64位,只有40个LSb的地址)中的地址所指向的32位数据。所以,我做的:当指针和数据宽度不同时指针间接寻址

paddr_t address = read_hw(); // paddr_t is unsigned long long 
unsigned int value = *(unsigned int*) address; // error: cast to pointer from integer of different size 
unsigned int value2 = (unsigned int) *((paddr_t*) address); // error: cast to pointer from integer of different size 

会是什么正确的方式来做到这一点没有编译器错误(我用-Werror)?

回答

1

名义上与C99的第一选择是最接近正确,

uint32_t value = *(uint32_t*)address; 

然而,你也可以选择使用其他的指针/整数帮手,

uintptr_t address = read_hw(); 
uint32_t value = *(uint32_t*)address; 
0

检查实际尺寸为您的指针和paddr_t类型:

printf("paddr_t size: %d, pointer size: %d\n", 
     sizeof(paddr_t), sizeof(unsigned int *)); 

你会得到什么?

更新:

ARM是32位架构,让你尝试从一个64位整数转换为32位指针的编译器不喜欢它!

如果你确信在paddr_t值在32位指针适合你可以将它转换为第一的int

unsigned int *p = (unsigned int *)(int)addrs; 
+0

我没有补充说我正在使用交叉编译器。所以我没有printf的奢侈! – Jeenu 2010-12-09 08:52:25

0

我不知道我理解的问题。 “我想要访问硬件寄存器中的地址指向的32位数据(它是64位,只有40 LSb的设置)”。

因此,您有一个64位宽的硬件寄存器,其中最不重要的40位应该被解释为内存中包含32位数据的地址?

你可以尝试

uint32_t* pointer = (*(uint64_t *) register_address) & (~0 >> 24) 
uint32_t value = *pointer 

虽然这可能会依赖于字节序和是否编译器把>>为逻辑或算术右移更加复杂。

虽然,说真的,我想问一下,

  1. 请问“我使用的是交叉编译器,我没有的printf的奢侈品”的意思是你不能真正运行代码,或只是你必须做一些缺乏方便的输出通道的硬件?
  2. 你的目标架构是什么,你的指针长度是40位?!
0

从你写的你有一个64指针,其中只有40位是指针,该指针指向一些32位大小的数据。

您的代码似乎试图将40位指针压入32位指针。

什么,你应该做的是&“荷兰国际集团的64位指针中的相关40位的,所以它仍然是一个64位的指针,然后使用来访问数据,然后你就可以同样&获取数据。否则你是(如错误指示)截断指针。

喜欢的东西(我没有64位,所以我不能对此进行测试,但你的想法):

address = address & 0x????????????????; // use the ?s to mask off the bits you 
             // want to ignore 
value64 = *address; // value64 is 64 bits 

value32 = (int)(value64 & 0x00000000ffffffff); // if the data is in the lower 
               // half of value64 
or 
value32 = (int)((value64 & 0xffffffff00000000) > 32); // if the data is in the 
                 // higher half of value64 

,其中根据需要的是屏蔽位(视?你正在使用的终结)。您可能还需要更改(int)强制转换以适应(您希望将其强制转换为数据表示的任何32位数据类型 - 即value32的类型)。