指向字节数组的指针

时间:2013-09-30 18:50:23

标签: c arrays pointers misra

由于Misra C要求,我的一位同事想要使用指针声明我遇到了一些麻烦。 Misra(安全关键指南)不会让程序员使用指针,而是让我们操作数组字节。他打算生成一个指向字节数组的指针(因此我们不会在堆栈上传递实际的数组。)

// This is how I would normally do it
//
void Foo(uint8_t* pu8Buffer, uint16_t u16Len)
{
}

// This is how he has done it
//
void Foo(uint8_t (*pu8Buffer)[], uint16_t u16Len)
{
}

调用函数看起来像;

void Bar(void)
{
    uint8_t  u8Payload[1024]
    uint16_t u16PayloadLen;

    // ...some code to fill said array...

    Foo(u8Payload, u16PayloadLen);
}

但是,当在Foo()中访问pu8Buffer时,数组是错误的。显然没有超越预期。数组在调用函数中是正确的,但不在Foo()

我认为他创建了一个指向字节的指针数组,而不是指向字节数组的指针。

有人在意澄清吗? Foo(& u8Payload,u16PayloadLen);也不起作用。

2 个答案:

答案 0 :(得分:4)

void Foo(uint8_t (*pu8Buffer)[], uint16_t u16Len)中,pu8Buffer是指向uint8_t的(不完整)数组的指针。 pu8Buffer的类型不完整;它是指向大小未知的数组的指针。它可能不适用于需要大小的表达式(例如指针算术;不允许pu8Buffer+1)。

然后*pu8Buffer是一个大小未知的数组。由于它是一个数组,因此在大多数情况下会自动转换为指向其第一个元素的指针。因此,*pu8Buffer成为指向数组的第一个uint8_t的指针。已转换*pu8Buffer的类型已完成;它是指向uint8_t的指针,因此可用于地址算术; *(*pu8Buffer + 1)(*pu8Buffer)[1]1[*pu8Buffer]都是uint8_t以外*pu8Buffer的有效表达式。

答案 1 :(得分:3)

我认为你指的是MISRA-C:2004规则17.4(或2012规则18.4)。甚至像我这样忠于MISRA的人也会发现这条规则完全是胡说八道。该规则的基本原理是这一点(MISRA-C:2012 18.4):

  

“使用数组下标语法的数组索引,ptr [expr],是   指针算术的首选形式,因为它通常更清晰   因此比指针操作更不容易出错。任何明确的   计算的指针值有可能无意中访问或   内存地址无效。阵列也可以实现这种行为   索引,但下标语法可以简化人工审查的任务。

     

C中的指针运算可能会让新手混淆表达式   ptr+1可能被错误地解释为添加1   ptr中的地址。实际上新的内存地址取决于   指针目标的大小(以字节为单位)。这种误解可能导致   如果未正确应用sizeof,则出现意外行为。“

所以这一切都归结为MISRA担心初学者程序员会混淆ptr + 1来获得我们在编写(uint8_t*)ptr + 1时会得到的结果。在我看来,解决方案是教育新手程序员,而不是限制专业程序员(但是如果你聘请新手程序员来编写符合MISRA标准的安全关键软件,那么理解指针算法可能是你问题中最不重要的)。

通过写出与此规则的永久偏差来解决此问题!


如果您因为未知的原因不想偏离,但要使您当前的代码符合MISRA,只需将该功能重写为

void Foo(uint8_t pu8Buffer[], uint16_t u16Len)

然后用pu8Buffer[something]替换所有指针算术。然后突然根据MISRA:2004示例套件,代码100%兼容MISRA。它在功能上也与你已有的100%相当。