Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C STM32与while循环代码相同,但编译为不同的汇编代码_C_Assembly_While Loop_Stm32_Cortex M - Fatal编程技术网

C STM32与while循环代码相同,但编译为不同的汇编代码

C STM32与while循环代码相同,但编译为不同的汇编代码,c,assembly,while-loop,stm32,cortex-m,C,Assembly,While Loop,Stm32,Cortex M,我正在STM32F41RE板(Cortex-M4)上学习RTOS。我使用MDK uVision v5。我在循环时遇到了C代码的问题。下面的代码在我的项目和讲师的项目(在Udemy上)中完全相同,但是,在编译两个项目(在我的PC上)后,汇编代码看起来不同。我想问是什么让这不一样。多谢各位 void osSignalWait(int32_t *semaphore) { __disable_irq(); while(*semaphore <=0) {

我正在STM32F41RE板(Cortex-M4)上学习RTOS。我使用MDK uVision v5。我在循环时遇到了C代码的问题。下面的代码在我的项目和讲师的项目(在Udemy上)中完全相同,但是,在编译两个项目(在我的PC上)后,汇编代码看起来不同。我想问是什么让这不一样。多谢各位

void osSignalWait(int32_t *semaphore)
{
    __disable_irq();
    while(*semaphore <=0)
    {       
            __disable_irq();        
            __enable_irq();
    }
    *semaphore -= 0x01;
    __enable_irq();
}
void osSignalWait(int32_t*信号量)
{
__禁用_irq();

虽然(*信号量由于您没有告诉编译器
信号量
可以在执行此函数期间更改,因此编译器决定优化您的代码,只加载一次信号量的值,并在while循环中使用其副本,然后只在最后写入结果。正如现在编写的那样,编译器没有理由不这样做o假设这可能是有害的

要通知编译器一个变量可能在函数外更改,请在该函数执行期间使用
volatile
关键字,请参阅:

在这种情况下,您的代码将变成:

void osSignalWait(volatile int32_t *semaphore)
{
    __disable_irq();
    while(*semaphore <=0)
    {       
        __disable_irq();        // Note: I think the order is wrong...
        __enable_irq();
    }
    *semaphore -= 0x01;
    __enable_irq();
}
void osSignalWait(volatile int32_t*信号量)
{
__禁用_irq();

虽然(*信号量这是一个众所周知的keil过度优化错误。报告了很多次。如果内存崩溃,它应该每次都读取内存

这里是一个例子,如何打击工作

#include <stdint.h>

unsigned x;
volatile unsigned y;


int foo()
{
    while(x < 1000);
}

int bar()
{
    while(x < 1000) asm("":::"memory");
}

不同的编译器版本?不同的编译器选项?嗨,因为老师从不回答学生,我必须在这里问这个问题。@PaulOgilvie我需要研究哪个编译器选项?谢谢you@Dung-在讲师的代码图像中,你没有显示函数的第一行。是的,这对我们很重要,因为我们不能假设任何事情ng.FWIW:我认为while循环的主体应该是
\uuuu enable\u irq();\uu disable\u irq()
按这个顺序。@Dung-Yi:调试器不知道。它只是重新加载,因为它必须是在没有优化的情况下编译的,所以编译器对待一切都像
volatile
。请参阅。或者特别是针对您和您的讲师代码中的错误:/顺便说一句,用于核心之间通信的可移植C选择/线程是
\u Atomic int32\u t*
(内存顺序放松)。(如果你禁用IRQ,你可以使用单独的原子加载和原子存储,而不是
-=
)。@Dung-Yi:Hmm,我想你的代码被破坏了:
while()
循环体在执行
-=
之前让中断处于启用状态。我想你需要
启用();disable();
作为循环体,在旋转等待时给中断处理程序一个运行的机会。或者更好,在启用中断的情况下旋转,直到看到
*sem@Elijan9-循环体当前禁用中断,然后启用它们,正如Peter Cordes提到的,这是反向的。循环体中那些中断的用途(按正确的顺序执行时)是为了确保当信号量可用时,循环体在中断被禁用的情况下退出。同时,反复启用它们可以确保在旋转等待期间可以为中断提供服务。非常感谢各位。基于我简单而有点傻的问题,我感谢你们的好意。(我已经做了将近一周的研究,但找不到正确的关键词来回答。我希望问题不会重复)@Dung Yi我不是说使用“协作自旋锁”。我不知道你在使用什么类型的RTO;也许是自制的?(你的教授写的吗?)任何好的商业RTO都会有“等待信号量”API函数,该函数使您的线程处于睡眠状态,直到另一个线程或中断提供信号量。当您的线程处于睡眠状态时,它根本不消耗CPU指令周期。使用屈服或延迟函数比普通旋转要好,但仍然需要间歇的CPU周期;它不如指定的API函数好Caly是为等待信号量而设计的。这不是一个过度优化的bug,它是C源代码中的数据竞争UB,您可以使用内存障碍或易失性来解决。或者使用
\u原子
避免UB(使用
MOU relaxed
,这样它就可以编译为相同的asm).你为什么说屏障比volatile或原子int更好?因为这是针对仅用于同步的信号量对象的,所以您永远不希望编译器跨多个读取将其保存在寄存器中。
volatile
确保我们不会从一次读取中获取数据。感谢您指出问题。我以前在堆栈溢出中发现过此错误,但从未意识到我的问题是这是由它引起的!!谢谢。@PeterCordes我没有说什么更好。它们并不完全相同,也有不同的用途@Dung Yi:只是要澄清一点;这不是编译器的错误,而是代码中的错误。编译器正在按预期工作,并在假设没有其他线程可以修改它们的情况下将变量优化到寄存器中,除非你告诉我否则。可以假设,对于非原子变量和非易失变量,因为。如果编译器不这样做,任何使用全局变量甚至指针的代码都会运行缓慢,每次更改后都会存储,每次使用前都会重新加载。@P_uj_uuuu:我想我是被上的注释线程搞混了另一个答案与此相反。但是当已经有一个答案建议
volatile
时,为什么要发布它呢?有趣的是
应该是
\u disable\u irq()
定义的一部分的
内存
屏障应该已经阻止了重新排序,就像在GCC上一样。(但我知道内存障碍不会影响非转义的局部变量,比如函数arg。)
void osSignalWait(volatile int32_t *semaphore)
{
    __disable_irq();
    while(*semaphore <=0)
    {       
        __disable_irq();        // Note: I think the order is wrong...
        __enable_irq();
    }
    *semaphore -= 0x01;
    __enable_irq();
}
#include <stdint.h>

unsigned x;
volatile unsigned y;


int foo()
{
    while(x < 1000);
}

int bar()
{
    while(x < 1000) asm("":::"memory");
}
foo:
        ldr     r3, .L5
        ldr     r3, [r3]
        cmp     r3, #1000
        bxcs    lr
.L3:
        b       .L3
.L5:
        .word   x
bar:
        ldr     r1, .L11
        ldr     r2, .L11+4
        ldr     r3, [r1]
        cmp     r3, r2
        bxhi    lr
.L9:
        ldr     r3, [r1]
        cmp     r3, r2
        bls     .L9
        bx      lr
.L11:
        .word   x
        .word   999