指针和数据宽度不同时的指针间接

时间:2010-12-09 08:41:10

标签: c

我想访问由硬件寄存器中的地址指向的32位数据(64位,仅设置40 LSb)。所以我这样做:

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)?

4 个答案:

答案 0 :(得分:1)

名义上使用C99,第一个选项最接近正确,

uint32_t value = *(uint32_t*)address;

但是,您也可以选择使用其他指针/整数助手

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

答案 1 :(得分: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;

答案 2 :(得分:0)

我不确定我理解这个问题。

“我想访问硬件寄存器中地址所指向的32位数据(64位,只设置40 LSb)。”

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

你能试试吗

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

虽然根据endian-ness以及编译器是否将>>解释为逻辑或算术右移,这可能会变得更复杂。

虽然,我想问一下,

  1. “我正在使用交叉编译器,我没有奢侈的printf”意味着你实际上无法运行你的代码,或只是你必须做一些缺乏方便的输出通道的硬件?
  2. 你的目标架构是什么,你的指针是40位长?!

答案 3 :(得分:0)

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

您的代码似乎试图将40位指针转换为32位指针。

你应该做的是在64位指针内放置相关的40位,使其保持64位指针,然后使用它来访问数据,然后你可以同样地&amp;获取数据。否则你(如错误所示)截断指针。

类似的东西(我没有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的类型)。