【C语言深入】指针的一个错误赋值

  版权信息:
● 本博客使用CC 3.0协议,转载请保留该信息。
● 原文作者: 戴晓天 @ 云飞机器人实验室
● 原文地址: 【C语言深入】指针的一个错误赋值

关于指针总是有说不完的故事。

最近给本科的学生带Embedded System课程设计,遇到了一个非常奇怪的bug。有一段代码需要实现I2C通信,核心代码已经由软件库提供了,学生只需要设置结构体后调用API即可。一个学生的代码是这样的:

<br />
struct I2C_CONFIG {<br />
  // ...<br />
  char *i2c_buff;<br />
  int length;<br />
  // ...<br />
};</p>
<p>struct I2C_CONFIG cfg;<br />
char *i2c_buff;</p>
<p>void I2C_init()<br />
{<br />
  // ...<br />
  cfg.buff = i2c_buff;<br />
  cfg.length = sizeof(buff);<br />
  // ...<br />
}</p>
<p>void I2C_send(new_buff)<br />
{<br />
  // ...<br />
  i2c_buff = new_buff;<br />
  I2C_MasterTransferData(LPC_I2C1, cfg);<br />
  // ...<br />
}<br />

初看一下没有什么问题:在I2C_init()函数中首先对结构体cfg进行初始化,而在I2C_send()函数中设置了需要发送的数据指针,之后使用I2C的API发送数据。

因为代码一直无法实现期望的功能,我又仔细看了一下其中的蹊跷。我注意到,这段代码中使用了一个中间变量:char *i2c_buff。在I2C_init()中虽然将cfg.buff指向了i2c_buff,但是因为cfg.buff本身也是指针变量,而非”指向指针的指针”,所以这里只实现了简单的按值传递,即将i2c_buff的值 (初始值为0) 赋给了cfg.buff。之后虽然在I2C_send()中修改了临时变量i2c_buff指向的位置,但却没有影响到cfg.buff中的内容,cfg.buff依然指向之前i2c_buff初始化时指向的内存地址,所以需要发送的缓冲指针new_buff其实并没有传递给之后的I2C_MasterTransferData()函数!为了解决这个问题,必须将更改后的i2c_buff的值再次赋给cfg.buff,即:

<br />
void I2C_send(new_buff)<br />
{<br />
  // ...<br />
  i2c_buff = new_buff;<br />
  cfg.buff = i2c_buff;<br />
  I2C_MasterTransferData(LPC_I2C1, cfg);<br />
  // ...<br />
}<br />

另外这段代码还有一个不容易注意的bug,就是在I2C_init()中使用了sizeof()来判断buffer的大小。因为sizeof()函数得到的只是数据类型的大小,所以对于指针char *i2c_buff来说,sizeof(i2c_buff) = 4,而不会返回buffer的实际大小。指针的大小并不等于指针指向缓冲的大小!

%d bloggers like this: