假设在简化乘法时不会发生有符号溢出

时间:2012-06-20 19:36:32

标签: c gcc

所以这个gcc警告困扰着我:

warning: assuming signed overflow does not occur when simplifying multiplication

它指向的代码如下所示:

/* Move the memory block of entries after the removed one - if any. */          
if (database->entries + database->entries_size - 1 != database_entry) {         
    memmove(                                                                    
        database_entry,                                                         
        database_entry + 1,                                                     
        sizeof(spm_database_entry_t)                                            
            * (                                                                 
                (database->entries + database->entries_size)                    
                - database_entry - 1                                            
            )                                                                   
    );                                                                          
}

正如您可以轻易猜到的那样,它会在元素移除后移动容器内存的一部分,以允许其进一步重新分配(缩小)。

  • database_entry是已移除元素
  • spm_database_entry_t*类型指针
  • database->entries是指向spm_database_entry_t
  • 数组的指针
  • database->entries_size是一个size_t代表<{>>元素 之前

如何摆脱警告?我可以阻止乘法简化,或者可能有更好的方法来计算需要移动的内存量吗?

修改

您确定database->entries

正。

您正在使用哪些编译器标志?

database_entry < database->entries + database->entries_size

EDIT2

在乘法之前转换为-Wall -Wextra -Wshadow -Wpointer-arith -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wdeclaration-after-statement -Wwrite-strings -Winit-self -Wcast-align -Wstrict-aliasing=2 -Wformat=2 -Wmissing-declarations -Wmissing-include-dirs -Wno-unused-parameter -Wuninitialized -Wold-style-definition -Wno-missing-braces -Wno-missing-field-initializers -Wswitch-default -Wswitch-enum -Wbad-function-cast -Wstrict-overflow=5 -Winline -Wundef -Wnested-externs -Wunreachable-code -Wfloat-equal -Wredundant-decls -pedantic -ansi -fno-omit-frame-pointer -ffloat-store -fno-common -fstrict-aliasing 似乎可以解决问题,但是转换为unsigned int则不行。我不明白 - 标准说size_t始终是无符号的......

EDIT3

如果上下文可以有用:https://github.com/msiedlarek/libspm/blob/master/libspm/database.c#L116

edit4

基于史蒂夫莎的回答的解决方案:

size_t

2 个答案:

答案 0 :(得分:2)

就个人而言,我赞成其他中间临时变量。编译器将看到它们仅用于一次计算,并将优化变量;但是在调试版本中,您可以单步执行,检查变量,并确保它确实按照您的预期进行。

/* Move the memory block of entries after the removed one - if any. */          
assert(database_entry >= database->entries &&
        database_entry < database->entries + database->entries_size);

size_t i_entry = database_entry - database->entries;
size_t count_to_move = (database->entries_size - 1) - i_entry;
size_t bytes_to_move = count_to_move * sizeof(spm_database_entry_t);
memmove(database_entry, database_entry + 1, bytes_to_move);                                                                          

大多数情况下,bytes_to_move不会为0,但如果为0,那么memmove()将只移动0个字节并且不会造成任何伤害。所以我们可以删除那个if语句,除非你内部有其他内容,只有在移动发生时才需要这样做。

此外,如果你这样做,并且你仍然收到警告,你将得到一个行号,指出编译器担心的是什么。

答案 1 :(得分:0)

我怀疑这个问题与size_t返回的sizeof(spm_database_entry_t)始终是无符号类型(通常只是unsigned intunsigned long int的类型同义词有关,如果我没记错的话)。但是,理论上有可能的是,如果database_entry的值超过database->entries + database->entries_size,您最终会将有符号数乘以无符号类型,从而增加了错误或整数溢出的可能性。通常,当有符号和无符号类型像这样混合时,较小的类型被转换/强制转换为较大的类型,或者,如果它们被同等地排序,则签名类型被强制转换为无符号类型。我不知道你的代码的其余部分是什么样的,因此很难提出改进建议。