2012-06-20 35 views
3

时假定有符号数从不溢出所以这是这个海湾合作委员会警告说,困扰我:简化乘法

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_entryspm_database_entry_t*类型的指针指向被删除的元素
  • database->entries是指向的spm_database_entry_t
  • database->entries_size阵列之前表示数字database->entries元件一个size_t除去

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

编辑

你肯定database_entry < database->entries + database->entries_size

正面。

什么是您使用的编译器标志?

-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 

EDIT2

乘法之前投放到unsigned int似乎做的伎俩,但铸造size_t没有。我不明白这一点 - 标准说size_t始终是无...

EDIT3

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

edit4

解决方案基于steveha的回答:

/* Calculate how meny entries need moving after the removal. */     
size_t entries_to_move = (                
    (database->entries + database->entries_size)         
    - database_entry - 1               
);                    

/* Move the memory block of entries after the removed one - if any. */   
memmove(                  
    database_entry,                
    database_entry + 1,               
    sizeof(spm_database_entry_t) * entries_to_move        
); 
+0

你确定'database-> entries + database-> entries_size - 1> database_entry'吗? – kennytm

+0

@KennyTM正面。 –

回答

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声明,除非你有其他东西在里面,只有当移动发生时才需要做。另外,如果你这样做,并且你仍然收到警告,你将得到一个行号,它将指示编译器担心什么。

+0

我接受你的答案,因为创建'size_t'类型的附加变量'entries_to_move',然后将它乘以入口类型的大小是恕我直言的干净的解决方案,并实际上解决了警告,所以你肯定让我在正确的轨道上。 –

0

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

+0

在'memmove'的时刻,我确定'database_entry'在'database-> entries'的范围内。我猜想的问题是如何告诉编译器。 –

+0

@MikołajSiedlarek,如果你完全确定溢出是不可能的,那么我相信你应该能够通过用'-fstrict-overflow'标志编译来阻止警告(也许启用一些编译器优化)。 –

+0

防止所有设置的警告摆脱一个?看起来不正确。我喜欢警告,他们在那里是有原因的。 –