1

考虑这段代码:

#define TRANSLATOR_requestElectricityMeterWrite()  do{addr = word_getAddress(); value = word_getValue(); }while(0)

uint16_t value;
uint8_t addr;

bool dispatcher(void)
{
    TRANSLATOR_requestElectricityMeterWrite(); 
    return true;
} // AFTER this point (during debug) program goes to default handler

int main(void)
{
   if(dispatcher())
      continue;
      . . . .
      . . . . 
}

uint16_t word_getValue(void)
{
    uint16_t value;
    sscanf("ABCD", "%4x", (unsigned int *)&value);
    return value;
}

uint8_t word_getAddress(void)
{
    uint8_t address;
    sscanf("00", "%2x", (unsigned int *)&address);
        ;
    return address;
}

当上面的代码运行时,里面的语句if会导致程序崩溃(转到某个默认处理程序)。

但是当我将这两个(word_getValue和 word_ getAddres)函数更改为:

uint16_t word_getValue(void)
{
    uint16_t value;
    int i = 0;i++;
    i = sscanf(WORD_getValueString(), "%4x", (unsigned int *)(&value));
    return value;
}

uint8_t word_getAddress(void)
{
    uint8_t address;
    int i = 0;i++;
    i = sscanf(WORD_getNameString(), "%2x", (unsigned int *)(&address));
    return address;
}

有用。添加假人i似乎可以解决该问题。但是为什么它不以另一种方式工作呢?

GNU ARM v4.8.3 工具链

4

2 回答 2

3

这两个函数都会调用未定义的行为,因此任何事情都可能发生。添加额外的局部变量会更改目标变量的位置,从而隐藏其大小不正确的影响。

sscanf("ABCD", "%4x", (unsigned int *)&value);

sscanf将字节(可能是 4 个)存储到只有 2 个字节的sizeof(unsigned int)变量中。value

sscanf(WORD_getNameString(), "%2x", (unsigned int *)(&address));

将字节存储到只有 1 个字节的sizeof(unsigned int)变量中。address

解决此问题的最简单方法是解析为 anunsigned int并将解析后的值分别存储到目标,或者简单地返回该值:

uint16_t word_getValue(void) {
    unsigned int value;
    if (sscanf(WORD_getValueString(), "%4x", &value) == 1)
        return value;
    // could not parse a value, return some default value or error code
    return 0;
}

uint8_t word_getAddress(void) {
    unsigned int address;
    if (sscanf(WORD_getNameString(), "%2x", &address) == 1)
        return address;
    // could not parse a value, return some default value or error code
    return 0;
}

您可能还想验证解析的值是否在目标类型的范围内,但由于您将解析分别限制为 4 和 2 个十六进制数字,因此不会发生溢出。

于 2016-08-12T12:52:37.793 回答
1

%x格式需要unsigned参数(假设它uint32_t在您的平台上)。如果你通过了uint16_t,否则uint8_t它会破坏内存。在您的情况下,它会损坏堆栈并覆盖返回地址。尝试使用%4hxforuint16_t%2hhxfor uint8_t

于 2016-08-12T12:47:58.457 回答