必须将函数 sscanf 分配给变量,否则会出现奇怪的行为
Function sscanf must be assigned to variable otherwise strange behavior
考虑这段代码:
#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;
}
有效。添加 if the dummy i
似乎可以解决该问题。但为什么它不能以其他方式工作?
GNU ARM v4.8.3 工具链
%x
格式需要 unsigned
参数(假设它在您的平台上是 uint32_t
)。如果你传递 uint16_t
或 uint8_t
它会破坏内存。在您的情况下,它会损坏堆栈并覆盖 return 地址。尝试对 uint16_t
使用 %4hx
,对 uint8_t
使用 %2hhx
。
这两个函数都会调用未定义的行为,因此任何事情都有可能发生。添加一个额外的局部变量会改变目标变量的位置,隐藏其不正确大小的影响。
sscanf("ABCD", "%4x", (unsigned int *)&value);
sscanf
会将 sizeof(unsigned int)
字节(可能是 4)存储到变量 value
中,它只有 2 个字节。
sscanf(WORD_getNameString(), "%2x", (unsigned int *)(&address));
将 sizeof(unsigned int)
字节存储到变量 address
中,该变量只有 1 个字节。
解决此问题的最简单方法是解析为 unsigned int
并将解析后的值单独存储到目标,或者简单地 return 值:
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 位十六进制数字,因此不会发生溢出。
考虑这段代码:
#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;
}
有效。添加 if the dummy i
似乎可以解决该问题。但为什么它不能以其他方式工作?
GNU ARM v4.8.3 工具链
%x
格式需要 unsigned
参数(假设它在您的平台上是 uint32_t
)。如果你传递 uint16_t
或 uint8_t
它会破坏内存。在您的情况下,它会损坏堆栈并覆盖 return 地址。尝试对 uint16_t
使用 %4hx
,对 uint8_t
使用 %2hhx
。
这两个函数都会调用未定义的行为,因此任何事情都有可能发生。添加一个额外的局部变量会改变目标变量的位置,隐藏其不正确大小的影响。
sscanf("ABCD", "%4x", (unsigned int *)&value);
sscanf
会将 sizeof(unsigned int)
字节(可能是 4)存储到变量 value
中,它只有 2 个字节。
sscanf(WORD_getNameString(), "%2x", (unsigned int *)(&address));
将 sizeof(unsigned int)
字节存储到变量 address
中,该变量只有 1 个字节。
解决此问题的最简单方法是解析为 unsigned int
并将解析后的值单独存储到目标,或者简单地 return 值:
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 位十六进制数字,因此不会发生溢出。