【问题标题】:Keil uVision5 armcc.exe: Problem with unsigned shorts in if statement not working correctly?Keil uVision5 armcc.exe:if 语句中未签名的短裤无法正常工作的问题?
【发布时间】:2021-05-21 23:40:29
【问题描述】:

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);

`

【问题讨论】:

  • 你为什么想要做例子#1(哪个工作)?它正在复制val16 - start_count 计算[并依靠优化器来解决这个问题]。示例 #2 是我首先要编写的代码,那么问题是什么?您提到HAL_GetTick 可以返回 32 位 [或 16 位],那么您/您将如何确定 your 变量是否可以 [仅] unsigned shortuint32_t。在任何情况下,您都有 unsigned 数量,即使使用 32 位,您也必须自己处理潜在的翻转。而且,newval - oldval 不会单独这样做。
  • 要处理翻转,请参阅我最近的回答:stackoverflow.com/questions/66124895/…
  • 这只是一个尝试理解这一点的测试。在这种情况下,翻转在无符号算术减法中应该无关紧要,我从来不需要单独管理它。
  • 如果你关心的只是算术,那就不是了。或者,短/增量间隔。但是,您有一个可以翻转的 32 位定时器/计数器。如果您需要高精度的绝对时间,您必须关心 [per my link]。

标签: c keil


【解决方案1】:

首先 - 不要在没有特殊需要的情况下使用较短的类型,因为这通常会增加 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

第二个循环使用无符号短类型,计算结果时不会隐式转换。

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, r2, #16
.L6:
        ldr     r3, [r1]
        sub     r3, r3, r2
        lsl     r3, r3, #16
        lsr     r3, 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, r3, r1
        cmp     r3, #99
        bls     .L12
        bx      lr
.L15:
        .word   tick

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

【讨论】:

  • 谢谢。我是这个处理器和编译器的新手。这只是一个测试,因为我昨天偶然发现了它,需要理解它。它不会是任何最终代码。我不明白答案。因为我也尝试将所有内容都转换回无符号短,即使在算术内部也是如此,但这没有区别。
  • 这也不起作用。 ' while ((unsigned short)(val16 - start_count)
  • 它有效。如果你想编程 uCs,你需要更好地学习 C godbolt.org/z/davbT9
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-05
  • 1970-01-01
  • 1970-01-01
  • 2019-07-23
  • 2015-01-01
  • 2019-05-15
  • 2015-09-27
相关资源
最近更新 更多