目前我对预处理器有一个非常奇怪的错误。我搜索过,找不到任何相关内容,因此想在此发布。 以下是我的示例代码
#include <stdio.h>
#define DDR_BASEADDR 0x000000000U + 128*1024*1024
int main()
{
uint32_t* test2 = (uint32_t*) DDR_BASEADDR;
uint32_t whatIsThis = DDR_BASEADDR;
uint32_t* test3 = (uint32_t*) whatIsThis;
printf( "%x %x %x %x\n\r", DDR_BASEADDR, test2, test3, whatIsThis);
return 0;
}
此代码的输出应全部为0x8000000
。
但是,输出为:8000000 20000000 8000000 8000000
。
我认为这不是导致此问题的数据类型,因为即使我将uint32_t* test2 = (uint32_t*) DDR_BASEADDR;
更改为int32_t* test2 = (int32_t*) DDR_BASEADDR;
我在Zedboard的ARM A9和C++ online compiler上测试了这一点并得到了相同的结果。 感谢您的时间和精力。
Thang Tran
答案 0 :(得分:8)
宏扩展为您提供
uint32_t* test2 = (uint32_t*) 0x000000000U + 128*1024*1024;
当你想要的时候
uint32_t* test2 = (uint32_t*) (0x000000000U + 128*1024*1024);
这就是为什么建议在宏定义中使用大量括号,或者 - 甚至更好 - 使用函数。
答案 1 :(得分:4)
你的宏扩展为:
uint32_t* test2 = (uint32_t*) 0x000000000U + 128*1024*1024;
这与执行此操作相同:
//Check multiply by sizeof at the end
uint32_t* test2 = (uint32_t *) (0x000000000U + 128*1024*1024 * sizeof(*test2));
因为指针类型的大小为sizeof(uint32_t)
,因此任何增加/减少操作都会乘以此大小。
你想要的是:
uint32_t* test2 = (uint32_t *) (0x000000000U + 128*1024*1024);
这意味着您首先计算地址,然后转换为所需的指针。
答案 2 :(得分:3)
这一点绝对没什么奇怪的:在这一行
uint32_t* test2 = (uint32_t*) DDR_BASEADDR;
施法指针操作应用于0x000000000U
,之后int
128*1024*1024
被添加到施法结果中,即
uint32_t* test2 = (uint32_t*) 0x000000000U + 128*1024*1024;
// ^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
// Pointer Offset
这意味着执行指针算术,因此在整数术语中,偏移值乘以sizeof(uint32_t)
,产生0x8000000
。
然而,在这一行
uint32_t whatIsThis = DDR_BASEADDR;
没有强制转换为指针,因此添加完全以整数形式完成。这就是sizeof(uint32_t)
没有乘法的原因,结果是0x20000000
。
如果您希望所有四种情况都打印800000000
,则转换为指针需要位于宏内:
#define DDR_BASEADDR ((uint32_t*)0x000000000U + 128*1024*1024)
和int32_t
的演员需要在whatIsThis
:
uint32_t whatIsThis = (uint32_t)DDR_BASEADDR;
但是,uint32_t
不是指针的可移植类型。请改用uintptr_t
。
答案 3 :(得分:1)
用
#define DDR_BASEADDR 0x000000000U + 128*1024*1024
代码行
uint32_t* test2 = (uint32_t*) DDR_BASEADDR;
扩展为
uint32_t* test2 = (uint32_t*) 0x000000000U + 128*1024*1024;
实际上是(因为指针运算的方式)
uint32_t* test2 = (uint32_t*) (0x000000000U + (sizeof(uint32_t) *(128*1024*1024));
或
uint32_t* test2 = (uint32_t*) (0x000000000U + (4 * 0x8000000));
这样可以提供 200 00000而不是 80 00000,当然也是十六进制格式。
将乘以4的十六进制乘以4的倍数,就像乘以16(十六进制乘以10乘以十进制)并除以4。
即它产生1/4的值,向左移动一个十六进制数字:80-> 200。
其他代码行以某种方式具有一对大括号()
的效果。
如果您使用
#define DDR_BASEADDR (0x000000000U + 128*1024*1024)
你应该没事,并且正如你已经证实的那样。
慷慨地使用牙箍是非常好的做法,特别是对于宏。
注意:您还应该更加小心printf并使用要打印的值的正确表示(请参阅注释和其他答案)。否则产生的 U ndefined B 行为是邪恶的! UB可能会导致各种不必要的和无法解释的事情。 但是,解释在这种特殊情况下得到的值不需要UB。 (你很幸运。)