GCC for ARM 报告警告 - 潜在的未初始化变量

GCC for ARM reports warning - potential uninitialized variable

这是生成警告的代码:'res' may be used uninitialized in this function [-Wmaybe-uninitialized]

lwdtcr_t
lwdtc_cron_parse_multi(lwdtc_cron_ctx_t* cron_ctx, const char** cron_strs, size_t ctx_len, size_t* fail_index) {
    lwdtcr_t res;

    ASSERT_PARAM(cron_ctx != NULL);
    ASSERT_PARAM(cron_strs != NULL);
    ASSERT_PARAM(ctx_len > 0);

    /* Parse all input strings, each to its own cron context structure */
    for (size_t i = 0; i < ctx_len; ++i) {
        if ((res = lwdtc_cron_parse_with_len(&cron_ctx[i], cron_strs[i], strlen(cron_strs[i]))) != lwdtcOK) {
            if (fail_index != NULL) {
                *fail_index = i;
            }
            break;
        }
    }
    return res;
}

断言参数宏定义为

#define ASSERT_PARAM(c)                     if (!(c)) { return lwdtcERRPAR; }
/* Footprint of function being called inside is */
lwdtcr_t
lwdtc_cron_parse_with_len(lwdtc_cron_ctx_t* ctx, const char* cron_str, size_t cron_str_len)

编译器

arm-none-eabi-gcc 10.3.1 20210824 (release)
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

我很难理解为什么会出现此警告?如果变量立即为 0 和 return,则断言将启动,这意味着 for 循环将始终执行至少一轮 - 当然如果它到达那个点 - 意味着 res 将在 return 语句处初始化。

一定有优化技巧 - 但我至少不知道 - 有什么线索吗?

lwdtcr_t是简单枚举。

如何重现

运行 代码来自这里:https://godbolt.org/z/9E1xdv4dc

从标志中删除“-Og”神奇地工作,没有任何错误

最小示例

#include <string.h>
#include <time.h>

typedef enum {
    lwdtcOK = 0x00,                             /*!< Everything is OK */
    lwdtcERR,                                   /*!< Generic error */
    lwdtcERRPAR,                                /*!< Invalid parameter passed to a function */
    lwdtcERRTOKEN,                              /*!< Token value is not valid */
} lwdtcr_t;

typedef struct {
    uint32_t flags;                             /*!< List of all sort of flags for internal use */
} lwdtc_cron_ctx_t;

lwdtcr_t    lwdtc_cron_parse_with_len(lwdtc_cron_ctx_t* ctx, const char* cron_str, size_t cron_str_len);

#define ASSERT_PARAM(c)                     if (!(c)) { return lwdtcERRPAR; }

lwdtcr_t
lwdtc_cron_parse_multi(lwdtc_cron_ctx_t* cron_ctx, const char** cron_strs, size_t ctx_len) {
    lwdtcr_t res;

    ASSERT_PARAM(cron_ctx != NULL);
    ASSERT_PARAM(cron_strs != NULL);
    ASSERT_PARAM(ctx_len > 0);

    /* Parse all input strings, each to its own cron context structure */
    for (size_t i = 0; i < ctx_len; ++i) {
        res = lwdtc_cron_parse_with_len(&cron_ctx[i], cron_strs[i], strlen(cron_strs[i]));
    }
    return res;
}

有旗帜-Wall -Werror -Wextra -Og

和编译器

arm-none-eabi-gcc 10.3.1 20210824 (release)
Copyright (C) 2020 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

它说 可能 使用未初始化。这意味着编译器不确定。有一个不同的警告,它说 is used uninitialized.

警告的目的是让你再看一遍代码,质疑自己。如果您已经这样做并且确信编译器在这种情况下是错误的,那么您可以忽略警告。

如果您不确定,请尝试查看编译器输出的反汇编列表。

我建议的一件事是,标准库中的宏 assert 有时会编译为错误检查代码,有时会编译为空,具体取决于编译器设置。使用断言作为宏名称的一部分意味着类似的行为,因此请检查您的构建设置。

这就是它的基本结构(您可以在发布之前自行完成此简化):

int f (unsigned int len) {
    int res;
    if (len == 0) return 99;
    for (unsigned int i = 0; i < len; ++i)
        res = i;
    return res;
}

这会产生类似的警告。

但是如果您将 res = i 替换为 res = 99,警告就会消失。所以它看起来像是编译器不是无限聪明的情况。在这种情况下花太多时间是不值得的;最简单的修复方法是使用 int res = 0; 进行初始化(并附上解释原因的注释)。