3

だから私を悩ませているこの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_entryspm_database_entry_t*削除された要素への型のポインタです
  • database->entriesの配列へのポインタですspm_database_entry_t
  • database->entries_size削除の数値要素をsize_t表しますdatabase->entries

警告を取り除く方法は?乗算が単純化されるのを防ぐことはできますか、それとも移動する必要のあるメモリの量を計算するためのより良い方法がありますか?

編集

よろしいです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                              
);
4

2 に答える 2

1

個人的には、中間の一時変数を追加することを好みます。コンパイラは、それらが 1 つの計算のみに使用されていることを認識し、変数を最適化して取り除きます。しかし、デバッグ ビルドでは、シングル ステップで変数を調べて、実際に期待どおりに動作していることを確認できます。

/* 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そのため、移動が発生したときにのみ実行する必要がある何かが内部にない限り、そのステートメントを削除できます。

また、この方法で実行してもまだ警告が表示される場合は、コンパイラが懸念していることを示す行番号が表示されます。

于 2012-06-20T21:14:45.097 に答える
0

size_tこの問題は、によって返されるが常に符号なし型であるという事実に関連していると思われます (記憶が正しければ、通常はorsizeof(spm_database_entry_t)の単なる型シノニムです)。ただし、理論的には、 の値がそれを超えると、符号付きの数量に符号なしの型を乗算することになり、バグや整数オーバーフローの可能性が高まる可能性があります。通常、このように符号付きと符号なしの型が混在すると、小さい方の型が大きい方の型にキャスト/強制されます。または、ランク付けが同じであれば、符号付きの型が符号なしに強制されます。コードの残りの部分がどのように見えるかわかりませんので、改善を提案することは困難です。unsigned intunsigned long intdatabase_entrydatabase->entries + database->entries_size

于 2012-06-20T19:47:46.803 に答える