什么可能导致 C 跳过 return 语句?

问题描述 投票:0回答:2

我正在用 C 语言为微控制器编程,所以我不确定这个问题是否属于这里或电子堆栈交换。如果这里不适合,请告诉我,我会将问题移到那里。

所以我有 C 语言的有限状态机。这个 FSM 负责通过 UART 检索数据。每个状态都会检索一些数据并对其执行一些检查。每个州都有三个可能的方向。如果接收到的数据有效,则进入下一个状态。如果没有,它将重复其状态。如果该状态重复一定次数,它将转为失败状态。为了指示这个方向,状态返回一个代码:

ok
err
repeat
。这适用于除最后一个州之外的所有州。在这里,当调用
return repeat
时,我可以看到调试器转到该语句,然后遍历函数的最后一个
}
,然后它转到内存中的随机位置,我只能在代码的反汇编视图中看到该位置作曲家工作室。有时这是 0x0 有时它是 RAM 中的随机内存,我看不到。

什么会导致这种奇怪的行为?我在 Code Composer Studio 中关闭了优化选项。

所有州都有这样的机构:

enum ret_codes fc_state(void) {
    uint8_t buf[250];
    static uint8_t fail_counter = 0;
    const uint8_t max_tries = 5;

    int ret = 0;
    while (ret == 0) {
        ret = UART_read(_uart, buf, sizeof(buf));
    }
    if (ret == UART_STATUS_ERROR) {
        return err;
    }

    /*
        perform tests on buf ...
    */
    if (testFailed) {
        fail_counter++;
        if (fail_counter == max_tries) {
            // Write DEN over UART ...
            return err;
        }
        // write NACK over UART ...
        return repeat; // I can see the debugger reaching this statement in the fc_state
    }
    // write ACK over UART ...
    return ok;
} // When debugging the debugger goes here after 'return repeat' and to a random location in memory after this
// In the other states it goes back to the main loop described further below after 'return repeat'

FSM 的代码如下所示:

enum state_codes { ipv, fup, fc, fail, succ, invalid };

enum ret_codes { ok, err, repeat };
struct transition {
    enum state_codes src_state; // source state
    enum ret_codes ret_code; // the code it returns
    enum state_codes dst_state; // the state it should transfer to if the previous mentioned code was returned
};

enum ret_codes ipv_state(void);
enum ret_codes fup_state(void);
enum ret_codes fc_state(void);
enum ret_codes fail_state(void);
enum ret_codes succ_state(void);

enum ret_codes (* states[])(void) = {ipv_state, fup_state, fc_state, fail_state, succ_state};

struct transition transition_table[] = {
    {ipv, ok, fup}, // when in the ipv state and ok is returned then go to fup state
    {ipv, repeat, ipv}, // This repeat works
    {ipv, err, fail},
    {fup, ok, fc},
    {fup, repeat, fup}, // This repeats works as well
    {fup, err, fail},
    {fc, ok, succ},
    {fc, repeat, fc}, // This repeat fails for some reason
    {fc, err, fail}
};
enum state_codes lookup_transitions(enum state_codes, enum ret_codes);

这些状态的主循环如下所示:

while (1) {
    state_fun = states[current_state];
    return_code = state_fun();
    if (current_state == fail) {
        return 1;
    }
    if (current_state == succ) {
        return 0;
    }
    current_state = lookup_transitions(current_state, return_code);
    if (current_state == invalid) {
        return 1;
    }
}

编辑:我在下面添加了lookup_transitions表。顺便说一句,FSM 的实现取自 https://stackoverflow.com/a/1371654/5600470。该代码是为 Texas Instruments 的带有 Arm Cortex-M4F CPU 的 CC2652R 编写的。

enum state_codes lookup_transitions(enum state_codes cur_state, enum ret_codes rc) {
    uint8_t i;
    for (i = 0; i < sizeof(transition_table); i++) {
        if (cur_state == transition_table[i].src_state && rc == transition_table[i].ret_code)
            return transition_table[i].dst_state;
    }
    return invalid; // the transition table is not configured correctly
}

这是 Code Composer Studio 反汇编查看器针对 fc_state 显示的内容:

505       enum ret_codes fc_state(void) {
          fc_state():
000529a0:   B500                push       {r14}
000529a2:   F1AD0D3C            sub.w      r13, r13, #0x3c
512           const uint8_t max_tries = 5;
000529a6:   2005                movs       r0, #5
000529a8:   F88D003B            strb.w     r0, [r13, #0x3b]
514           int ret = 0;
000529ac:   2000                movs       r0, #0
000529ae:   9000                str        r0, [r13]
515           while (ret == 0) {
000529b0:   9800                ldr        r0, [r13]
000529b2:   B948                cbnz       r0, #0x529c8
516               ret = UART_read(_uart, &rheader, sizeof(rheader));
          $C$L62:
000529b4:   4829                ldr        r0, [pc, #0xa4]
000529b6:   6800                ldr        r0, [r0]
000529b8:   A901                add        r1, r13, #4
000529ba:   222B                movs       r2, #0x2b
000529bc:   F003FFC6            bl         UART_read
000529c0:   9000                str        r0, [r13]
515           while (ret == 0) {
000529c2:   9800                ldr        r0, [r13]
000529c4:   2800                cmp        r0, #0
000529c6:   D0F5                beq        $C$L62
518           if (ret == UART_STATUS_ERROR) {
          $C$L63:
000529c8:   9800                ldr        r0, [r13]
000529ca:   F1B03FFF            cmp.w      r0, #-1
000529ce:   D101                bne        $C$L64
519               return err;
000529d0:   2001                movs       r0, #1
000529d2:   E040                b          $C$L70
522           ret = 0;
          $C$L64:
000529d4:   2000                movs       r0, #0
000529d6:   9000                str        r0, [r13]
523           while (ret == 0) {
000529d8:   9800                ldr        r0, [r13]
000529da:   B958                cbnz       r0, #0x529f4
524               ret = UART_read(_uart, &last_fup_info, rheader.length);
          $C$L65:
000529dc:   481F                ldr        r0, [pc, #0x7c]
000529de:   F8BD202D            ldrh.w     r2, [r13, #0x2d]
000529e2:   6800                ldr        r0, [r0]
000529e4:   F10D012F            add.w      r1, r13, #0x2f
000529e8:   F003FFB0            bl         UART_read
000529ec:   9000                str        r0, [r13]
523           while (ret == 0) {
000529ee:   9800                ldr        r0, [r13]
000529f0:   2800                cmp        r0, #0
000529f2:   D0F3                beq        $C$L65
526           if (ret == UART_STATUS_ERROR) {
          $C$L66:
000529f4:   9800                ldr        r0, [r13]
000529f6:   F1B03FFF            cmp.w      r0, #-1
000529fa:   D101                bne        $C$L67
527               return err;
000529fc:   2001                movs       r0, #1
000529fe:   E02A                b          $C$L70
530           if (
          $C$L67:
00052a00:   4817                ldr        r0, [pc, #0x5c]
00052a02:   F8DD1037            ldr.w      r1, [r13, #0x37]
00052a06:   6800                ldr        r0, [r0]
00052a08:   4288                cmp        r0, r1
00052a0a:   D115                bne        $C$L68
00052a0c:   4815                ldr        r0, [pc, #0x54]
00052a0e:   F8DD1037            ldr.w      r1, [r13, #0x37]
00052a12:   6800                ldr        r0, [r0]
00052a14:   4288                cmp        r0, r1
00052a16:   D10F                bne        $C$L68
00052a18:   4813                ldr        r0, [pc, #0x4c]
00052a1a:   F8DD1033            ldr.w      r1, [r13, #0x33]
00052a1e:   6800                ldr        r0, [r0]
00052a20:   4288                cmp        r0, r1
00052a22:   D109                bne        $C$L68
00052a24:   4811                ldr        r0, [pc, #0x44]
00052a26:   F8DD1033            ldr.w      r1, [r13, #0x33]
00052a2a:   6800                ldr        r0, [r0]
00052a2c:   4288                cmp        r0, r1
00052a2e:   D103                bne        $C$L68
535               UPDATEMNGR_writeAck();
00052a30:   F001F834            bl         UPDATEMNGR_writeAck
536               return ok;
00052a34:   2000                movs       r0, #0
00052a36:   E00E                b          $C$L70
539           fail_counter++;
          $C$L68:
00052a38:   490D                ldr        r1, [pc, #0x34]
00052a3a:   7808                ldrb       r0, [r1]
00052a3c:   1C40                adds       r0, r0, #1
00052a3e:   7008                strb       r0, [r1]
540           if (fail_counter != max_tries) {
00052a40:   480B                ldr        r0, [pc, #0x2c]
00052a42:   7800                ldrb       r0, [r0]
00052a44:   2805                cmp        r0, #5
00052a46:   D003                beq        $C$L69
541               UPDATEMNGR_writeNAck();
00052a48:   F001F8BC            bl         UPDATEMNGR_writeNAck
542               return repeat;
00052a4c:   2002                movs       r0, #2
00052a4e:   E002                b          $C$L70
544           UPDATEMNGR_writeDen();
          $C$L69:
00052a50:   F001F86E            bl         UPDATEMNGR_writeDen
545           return err;
00052a54:   2001                movs       r0, #1
546       }
          $C$L70:
00052a56:   B00F                add        r13, #0x3c
00052a58:   BD00                pop        {pc}
00052a5a:   46C0                mov        r8, r8
c memory enums state-machine fsm
2个回答
0
投票

fc 和重复枚举都变成相同的整数,因为它们在枚举列表中处于相同的位置。您可以通过将枚举设置为不重叠的不同起始值来解决此问题。这就是第二次重复失败的原因。


0
投票

这个问题有点过时了,但是lookup_transitions()函数中有一个错误。循环变量可以迭代超出数组边界,并且函数可以从意外的内存位置返回值。这可能是通过无效指针和未定义行为调用函数的原因。我认为修复应该是这样的:

 for (i = 0; i < sizeof(transition_table) / sizeof(struct transition); i++) 
© www.soinside.com 2019 - 2024. All rights reserved.