2017-07-25 121 views
-3

我遇到了一些使用gcc编译器构建的C代码的问题。有问题的代码有一个枚举,其值在switch语句中用作配置对象的情况。相当标准的东西。GCC优化标志问题

当我使用-O0选项标记编译代码时,所有内容都可以正确构建并正确运行,而不会出现任何问题。但是,如果标志设置为-O2,代码将不再按预期工作。

当我浏览代码并在本地变量上加上监视时,枚举应该只是三个枚举值之一,实际上是-104!这会导致程序无法配置对象。

有没有人遇到过这个问题谁能提供一些指导?我之前没有遇到过这种情况,希望有人能解释为什么编译器会这样做,以便我可以做出任何必要的更改。有问题的代码

段:

value = 0u; 

switch(test_config) { 
    case DISABLE: 
     break; 

    case INTERNAL: 
     value = 1u; 
     break; 

    case EXTERNAL: 
     value = 2u; 
     break; 

    default: 
     valid = FALSE; 
     break; 
} 

if (valid) { 
    configure_test(value); 
} 

的枚举问题:

typedef enum { 
    DISABLE, 
    INTERNAL, 
    EXTERNAL 
} test_config_t; 

这是导致该问题的代码。我最初没有包含它,因为我不希望这个问题是请修复我的代码,而是一直在寻找原因,为什么gcc优化标志会为同一段代码产生不同的结果,并且没有发现任何东西特别有用。此外,我不在我的电脑上,不得不在我的手机上输入这也无济于事。所以我来到这里是因为这里有专家比我更了解方式,可以指引我走向正确的方向。

一些更多的信息,我可能应该包括在内。代码在硬件上运行也可能是问题,我也在考虑这个问题。当从FSBL运行时,代码与-O0协同工作,但不与-O2协同工作。所以它可能是硬件,但是我不知道为什么它的工作方式不是另一种。

+2

你可以请你发布你的代码吗? – Gaurav

+2

是的,使用优化选项时,包含buggy语句/未定义行为的代码可能会中断。不要发布你的代码,而是发布[mcve]。 –

+2

当然是UB。但我们无法知道为什么凭空而至。 – Quentin

回答

1

你不给足够的细节(因为你的问题没有显示任何实际的代码,它应该有一些MCVE),但你很可能有一些undefined behavior,你应该scared

记住C11C99(最喜欢的programming languages)由明确规范中定义(不仅是在你的代码中观察到的具体行为)以英语书写,部分定义一个有效的C程序的运行时行为。阅读​​。

我强烈建议您在阅读或编译源代码之前阅读Lattner的博客What Every C programmer should know about Undefined Behavior

我推荐至少编译(几乎)所有的警告和调试信息,例如与gcc -Wall -Wextra -g,然后改进代码以获得没有警告,并在gdb调试器和valgrind下运行它。阅读更多关于Invoking GCC。您也可以使用(临时)一些消毒剂instrumentation options,特别是-fsanitize=undefined-fsanitize=address。您还可以将-std=gnu99-pedantic添加到您的编译器标志。请注意,gdbwatchpoints是一个非常有用的调试器功能,可以查找值为什么已更改或意外。

当您针对版本进行编译或针对启用优化的基准测试时,请同时保留警告标志(以便与gcc -O2 -Wall -Wextra进行编译);优化可能会提供额外的警告,您还应该更正这些警告。顺便说一下,GCC同时接受-O2-g

当您观察到这些问题时,请在怀疑编译器之前先问自己的代码
(因为编译器经过了很好的测试;在编程的近40年中我发现只有一个编译器错误)。

+1

您还需要'-pedantic'和一些'-std'选项,例如'-std = gnu99'。 – melpomene

+0

有人可能想要使用GNU扩展,这是'-pedantic'禁止的。 –

+0

'-pedantic'不禁止GNU扩展。 – melpomene