Keil uVision5 armcc.exe:if 语句中的无符号短裤问题无法正常工作?

问题描述

armcc.exe V5.06 (750) 请让我知道为什么一旦 val16 溢出并变得小于 start_count,标记错误代码就不起作用。循环不再退出

HAL_GetTick() 返回 uint32_t(或 int)

unsigned short start_count;

unsigned short val16;
unsigned short result;

start_count = HAL_GetTick(); 

//This does not work
do
{
    val16 = HAL_GetTick();
    result = val16 - start_count;
}
while ((val16 - start_count)  < 100);  //this part does not work correctly 
                                       //when val16 overflows

//This works!  same code logic
do
{
    val16 = HAL_GetTick();
    result = val16 - start_count;
}
while (result  < 100);

`

解决方法

首先 - 不要在没有特殊需要的情况下使用较短的类型,因为它通常会在 32 位 RISC 目标上增加额外的开销。

第一个 while 不起作用,因为算术是使用整数而不是无符号短值完成的,给出了意想不到的结果:)。这里有一个演示程序:

unsigned HAL_GetTick(void)
{
    static unsigned tick = 65535 - 5;
    return tick++;
}

int main(void)
{
    unsigned short val16;
    unsigned short result;
    unsigned short start_count;

    start_count = HAL_GetTick(); 

    //This does not work
    do
    {
        val16 = HAL_GetTick();
        result = val16 - start_count;
        printf("%d %d\n",(val16 - start_count)  < 100,(val16 - start_count));
    }
    while ((val16 - start_count)  < 100);  //this part does not work correctly 
                                        //when val16 overflows

    //This works!  same code logic
    do
    {
        val16 = HAL_GetTick();
        result = val16 - start_count;
    }
    while (result  < 100);
}

https://godbolt.org/z/fa5M7W

第二个循环使用 unsigned short 类型,并且在计算结果时不会隐式转换。

https://godbolt.org/z/6TshP8

现在是使用 ARM Cortex 内核的非本机整数的问题。

示例程序:

volatile uint32_t tick;

uint32_t HAL_GetTick(void)
{
    return tick;
}

void foo(void)
{
    unsigned short val16;
    unsigned short result;
    unsigned short start_count;

    start_count = HAL_GetTick(); 


    //This works!  same code logic
    do
    {
        val16 = HAL_GetTick();
        result = val16 - start_count;
    }
    while (result  < 100);
}

void bar(void)
{
    uint32_t val16;
    uint32_t result;
    uint32_t start_count;

    start_count = HAL_GetTick(); 


    //This works!  same code logic
    do
    {
        val16 = HAL_GetTick();
        result = val16 - start_count;
    }
    while (result  < 100);
}

和结果代码:

foo:
        ldr     r1,.L9
        ldr     r2,[r1]
        lsl     r2,r2,#16
        lsr     r2,#16
.L6:
        ldr     r3,[r1]
        sub     r3,r3,r2
        lsl     r3,#16
        lsr     r3,#16
        cmp     r3,#99
        bls     .L6
        bx      lr
.L9:
        .word   tick
bar:
        ldr     r2,.L15
        ldr     r1,[r2]
.L12:
        ldr     r3,[r2]
        sub     r3,r1
        cmp     r3,#99
        bls     .L12
        bx      lr
.L15:
        .word   tick

如您所见,使用 16 位整数的版本效率低于使用 32 位本机大小整数的版本。