2016-04-30 9 views
6

最近cppcheckは、構造を有するもの、いくつかのCコードでエラーが発生した:これは2行に分割することができるCでのカンマ演算子と代入による評価の順序は予測可能ですか?

((void)(value_prev = value), value = new_value()) 

ほとんどの場合が、しかしいくつかの場合があり、これは単一の文を持っていることが有用です。

これは実際には、警告が表示されない一般的なコンパイラ(GCC/Clang/MSVC)で動作します。(警告レベルが最高に設定されていても)


例コード:

#include <stdio.h> 

int get_next(int i); 

int main() { 
    int i = 0, i_prev = 10; 
    do { 
     printf("%d\n", i); 
    } while ((void)(i_prev = i), 
      (i = get_next(i)) != 10); 
} 

CppCheck 1.73 (執筆時点での最新)は、このコードのエラーを与える:

(error) Expression '(void)(i_prev=i),(i=get_next(i))!=10' 
depends on order of evaluation of side effects` 

コードは静かに変更することができますが警告は、本当に未定義ですか?

+1

#define getnext(i)i ++のように、get_next(i)がマクロである可能性はありますか? – gnasher729

+1

いいえ、この場合は関数として定義されていますが、cppcheckは何も変更せずにこのコードでエラーを返します。 – ideasman42

答えて

8

順序は、それらの間にシーケンスポイントがあるために定義されます。 ISO/IEC 9899 6.5.17を参照してください。

カンマ演算子の左オペランドは、空白として評価されます。 ;評価の後にシーケンスポイントがあります。次に、 右のオペランドが評価されます。結果は型と値を持ちます。 95) コンマ演算子の結果を変更しようとした場合、または次のシーケンスポイント後に にアクセスしようとすると、その動作は未定義です。

そして、彼らは、明示的な例を与える:関数呼び出し
f(a, (t=3, t+2), c)
で関数三個の 引数、値5

を有する第二を有する

をなぜ私はCppCheckがそれにフラグを立てているのか完全にはわかりません。

+0

シーケンスポイントはC++言い回しではありませんか? – Alex

+0

@Alexもしそうなら、C99はそれをC++から借りた。私は比較するC99よりも前のC仕様を持っていません。 –