为什么即使请求,也没有gcc抱怨数组边界?

时间:2017-09-26 08:23:19

标签: c++ g++ compiler-warnings

我正在使用gcc 4.9.0,我希望看到编译器警告我超出数组范围。如果我编译这个

int main()
{
    int table[5]={0};
    table[8] = 1234;
    int x = table[10];
}

使用g ++ -O2 -Wall main.cpp -o main.exe我只收到有关未使用x的警告:

main.cpp: In function 'int main()':
main.cpp:8:7: warning: unused variable 'x' [-Wunused-variable]
int x = table[10];
   ^

从gcc文档(https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html#Warning-Options)我看到-O2和-Wall应该启用-Warray-bounds = 1 check。如果我尝试添加-Warray-bounds,事情就不会改变。事实上,编译器甚至无法识别-Warray-bounds = 1:

g++: error: unrecognized command line option '-Warray-bounds=1'

现在,为什么编译器没有给出关于错误地写入/读取数组的警告?为什么编译器不识别' -Warray-bounds = 1'?

3 个答案:

答案 0 :(得分:2)

我怀疑缺少警告是因为优化。编译器很容易看到你编写的所有行都没有对程序的行为产生任何影响,因此可能选择简单地跳过这些行。

在删除未使用的代码之后,似乎已经执行了检查已知超出绑定访问的编译时间的阶段,因此GCC从未看到您的错误。

防止此类优化的一种简单方法是声明数组volatile。任何volatile对象的写入或读取都必须被编译器视为副作用,因此无法进行优化。

答案 1 :(得分:1)

可能编译器会优化它。尝试制作table volatile

int main()
{
    volatile int table[]={0,0};
    table[8] = 1234;
    int x = table[10];
}

产生:

prog.cc:4:12: warning: array subscript is above array bounds [-Warray-bounds]
     table[8] = 1234;
     ~~~~~~~^
prog.cc:5:21: warning: array subscript is above array bounds [-Warray-bounds]
     int x = table[10];
             ~~~~~~~~^

这里是live example

来自-Warray-bounds文档:

  

它警告有关总是超出界限的数组的下标

我的猜测是,当访问从未真正发生时,g ++决定不发出警告。

  

事实上,编译器甚至无法识别-Warray-bounds = 1:

     

g++: error: unrecognized command line option '-Warray-bounds=1'

g ++ - 4.9.0不支持-Warray-bounds=n格式的命令,但它可以与-Warray-bounds一起使用。 g ++ - 5.1.0支持-Warray-bounds=n

答案 2 :(得分:0)

感谢您的回答。可能你对优化是正确的。如果我将表声明为volatile,那么我会得到警告"数组下标高于数组边界" 当我使用" -O2 -Wall"进行编译时或" -O2 -Warray-bounds"。但我仍然想知道为什么" -O2 -Warray-bounds = 1"产生错误

 private void insertEntity(final AbstractEntity entity) {
    insertedEntities.add(entity.getId());

    final List<AbstractEntity> relations = entity.onBeforeInsertion();
    for (final AbstractEntity relation : relations) {
        if (!insertedEntities.contains(relation.getId())) {
            insertEntity(relation);
        }
    }

    final RelationBundle relationBundle = new RelationBundle();
    entity.onInsertion(relationBundle);

    immediatelySaveNewEntityThroughProxy(entity);

    for (final AbstractEntity relation : relations) {
        entity.onRelationInsertion(relation, relationBundle);
    }

    dao.saveOrUpdate(entity);
}


private void immediatelySaveNewEntityThroughProxy(final DocumentEntity entity) {
    proxiedAccess().immediatelySaveNewEntity(entity);
}

private MyConsumer proxiedAccess() {
    return applicationContext.getBean(getClass());
}

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void immediatelySaveNewEntity(final DocumentEntity entity) {
    try {
        if (!dao.entityExistsFromId((int) entity.getId())) {
            dao.save(entity);
        }
    } catch (final Exception e) {
        LOGGER.error("Error saving entity: {}", entity.getId(), e);
    }
}