C指针转换 - 值截断

时间:2016-11-11 22:06:37

标签: c pointers

问题

这是将指向16位值的指针转换为指向32位值的指针的代码:

int low_level_read(uint32_t * read_data)
{
   // some low level access to get 32-bit read here
}

int i2c_read(uint16_t * data)
{
   low_level_read((uint32_t *) data);

   printf("data=0x%X\n", *data);
}

预期:

  • low_level_read获取:0x0000C101
  • i2c_read获得:0xC101

观察到的:

  • low_level_read获取:0x0000C101
  • i2c_read获得:0x0000

为什么它会截断/切断最不重要的 16位?

我对此问题的解决方案

如果将i2c_read()修改为如下所示,则按预期工作:

int i2c_read(uint16_t * data)
{
   uint32_t raw_data;
   low_level_read(raw_data);

   *data = (uint16_t) raw_data;
}

这很好,但我仍然想了解为什么第一段代码就像那样。

我的教育猜测为什么

当我们传入指向i2c_read()的指针时,它意味着8位:

pointer address 0x100 ->
+--+--+--+--+--+--+--+--+
  7  6  5  4  3  2  1  0
+--+--+--+--+--+--+--+--+

然而,当转换为(uint32_t *)时,它“增长”内存位置可以容纳32位的大小:

pointer address 0x100 ->
+--+--+--+--+--+--+--+--+    +--+--+--+--+--+--+--+--+
 31 30 29 28 27 26 25 24 ....  7  6  5  4  3  2  1  0
+--+--+--+--+--+--+--+--+    +--+--+--+--+--+--+--+--+

将32位值放入该位置。 但是当它截断它时,它实际上会截断位[15:0]并将指针地址保留为0x100。这意味着当它返回时,我最终会看到什么是位[31:16]因此全部为零。

这是我最好的猜测。

有人可以解释一下吗?谢谢:)。

1 个答案:

答案 0 :(得分:1)

i2c_read()正在接收参数uint16_t *data,其中说“这是一个2字节内存的地址”:

data --> [ByteA][ByteB]

执行转换(uint32_t*)data时,您现在声称data是4字节内存的地址:

data --> [ByteA][ByteB][ByteC][ByteD]

善意地,low_level_read()使用您作为uint32_t*传递的地址,并将所有4个字节的内存填充为[00][00][C1][01]这很糟糕。指针data无法[ByteC][ByteD],现在你已经覆盖了可能为程序的其他部分保存了一些重要数据的内存。

返回i2c_read()的{​​{1}},变量printf()又回到datauint16_t*只读*data要打印的值([ByteA][ByteB]) 如果您改为调用[00][00],则会读取4个字节并打印printf("℅08X", *(uint32_t*)data)

要修复代码,请确保0x00000C01i2c_read()的参数类型相同。