2013-11-14 7 views
6

MC9S12C32マイクロコントローラ用の埋め込みCコードでは、静的サイズのバイト配列とキューの前後に2つの "ポインタ"を使用して循環キュー(別名循環バッファ)実際にはキューの配列のインデックスにすぎません。 trearが後部要素の実際の指標であるが、tfrontは、前部要素(コースの16を法とする被験者)の実際の屈折率よりも小さいものであることC unsigned modulusによってコンパイラの警告が発生する

// call unsigned chars bytes 
typedef unsigned char byte; 
byte trear = 0; // SCI transmit display buffer IN index 
byte tfront = 0; // SCI transmit display buffer OUT index 
byte tsize = 16; // size of transmit buffer 
byte tbuf[16]= {0};// SCI transmit display buffer 

注意。だから私のバッファが「こんにちは」含まれている場合(空スロットがガベージ値である)、例えば、それは次のようになります。

:それはキューからバイトを削除する時が来たとき

_________________________________ 
| | |h|e|l|l|o| | | | | | | | | | 
^  ^
front  rear 

、私はこれを行います

// increment front index 
tfront++; 
// wrap front index if it exceeded bounds 
tfront %= tsize;       // (A) 
// get character to transmit 
byte outputChar = tbuf[tfront]; 

これはすべて問題なく動作します。少なくとも、私のプログラムではこのフラグメントに関するバグはありませんでした。私はこのプログラムをコンパイルするときしかし、私のコンパイラがラインについて私に警告文句、上記の断片で(A)をマーク:

警告:C2705:データ

main.cのライン損失の可能性402

行402は行(A)です。私はgccなどを使用していないことに注意してください。私はFreescaleのCodeWarrior IDEでコンパイルしています。これは、時には他にも幾分不思議な警告を与えています。警告を取り除くための試みで、私は、上記のようフラグメントを書き直し:

// increment front index mod tsize 
tfront = (tfront + 1 >= tsize) ? 0 : tfront + 1;  // (B) 
// get character to transmit 
byte outputChar = tbuf[tfront]; 

しかし、私のコンパイラは、まだ、ライン(B)については、この時間を同じ警告を発します。コンパイラが、文の中で(tfront + 1 >= tsize)tfrontが実行前に255であり、オーバーフローしている可能性があります。もちろん、私はこれが起こらないことを知っていますが、私のコンパイラはしません。

この場合、なぜ(A)という行が問題になったのですか?基本的に、私はコンパイラが何を不幸にしているか知りたい。


私の質問を入力して以来、私は、プリプロセッサの定義(すなわち、#define TSIZE 16)に変数の型からtsizeを変更することによってそれを解決してきました。私の質問はまだ立っている。


いくつかの関連質問:
unsigned overflow with modulus operator in C
modulus operator with unsigned chars

+1

注キャストなしのこの警告。したがって、16要素のバッファに対しては、 'tfront%= 16'ではなく' tfront | = 0x0f'となります。一般的には、2の累乗である 'tsize 'があれば、必要なmod-maskは' tsize - 1'です。 – Clifford

+0

@Clifford警告が、 'lval = expr;' lval'型が 'byte'型で' expr'型が 'int'型に拡張されていることによって引き起こされる警告の場合、ビットマスクを使用しても、 'tfront&mask;'は 'tfront%t'が(C99 6.3.1.1:2と6.3.1.8:1)と同じ理由で' tfront = tfront & mask; 'に展開し、' tfront&mask'は 'int '型を持ちます。整数昇格は両方のオペランドで実行されます) ")。 –

+0

@Cliffordさらに、ビットごとの演算子を正しく取得する必要があります。あなたは '&'を意味しましたか? –

答えて

5

コンパイラの警告の可能性が高いので、Cでのプロモーションルールのtfront = tfront % tsize;に相当しtfront %= tsize;、で表現tfront % tsizeは(持っているという事実から来ています*)タイプint

代わりにtfront = (byte)(tfront % tsize);を書き込むと、コンパイラがサイレントになることがあります。

あり心配する特別な理由はありません、そして、あなたのコンパイラは確かに奇妙な警告を発する:表現tfront % tsizeは技術的理由は、それが計算されている方法のbyteにその値が、すべてのフィットをintを入力しているが。値がすべてbyteに収まらない場合でも、ラップアラウンドの動作は、符号なし整数型のC標準によって保証されています(目的に合わせてこのラップアラウンド動作を使用することが正当化されます)。

(*)あなたのコンパイルのプラットフォーム上でintは、それがタイプunsigned intであろうと、あなたはおそらく、警告は表示されません。その場合にはunsigned charが取ることができるすべての値を含めることはできません場合を除きます。

+0

提案したとおり、これは問題のようです。非常に洞察力のある、ありがとう。 – ravron

+2

警告は単独では役に立たない。偽陽性は偽陰性よりも悪くなります。なぜなら、警告なしのコンパイルが良いという考え方を損なうからです。コンパイラのサプライヤにバグを報告してください。 –

+0

@JonathanLeffler私はすでにこの非常にバグを数年前に自分自身で報告しました。まだそこにいるかどうかはわかりません。詳細は私の答えを見てください。 – Lundin

3

この警告は、すべてのCodewarriorコンパイラの既知のバグです。データの警告の可能性のある喪失は、一貫性がなく、バグがあります。暗黙的なタイプのプロモーションのリスクがあるため警告することもありますが、そうでない場合もあります。 this discussionを参照してください。私はこれがS12CのCW(少なくともバージョン5.1までは私が使用しているもの)にも当てはまることを確認できます。

この警告を無効にすることはできますが、誤った警告とともに危険なコードが見つかることがあるため、この警告は推奨しません。あなたの特定のケースでは、警告は正しいです。

明示的なキャストなしで小さな整数型の演算をしています。そのようなコードは危険であり、隠されたバグを含んでいる可能性があります。なぜなら、Cは小さな整数を符号付き整数に昇格させるからです。明示的なキャストを強制するMISRA-Cのようなコーディング標準がここで助けになっていました。

さらに、?:演算子は、それがどのように動作するか分からない限り危険です。 2番目と3番目のオペランドのバランスをとっており、おそらく期待していなかったでしょう。

Iゆえにコードを変更することを示唆している: `tsize`が2のべき乗であることを保証することができれば、ビットマスクを使用する方が効率的であり、そしてそれはまたきちんと避けること

tfront = (byte)(tfront % tsize); 
... 

if((byte)(tfront +1) >= tsize) 
{ 
    tfront = 0; 
} 
else 
{ 
    tfront++; 
} 
+0

私はあなたの '(byte)(tfront +1)> = tsize'提案では納得できません。問題の元の状態と異なる必要がある唯一の機会は、 '(byte)(tfront +1)'が 'tfront + 1 'と異なる場合です。そうであれば、提案された条件の結果はおそらくプログラマーが意図したもの。あなたは、コンパイラの警告事項を無視して、通常は1つもなかったバグを起こさないようにしていますか?型をマッチさせたい場合、 '(unsigned int)tfront +1> =(unsigned int)tsize'がおそらく良いでしょう。 –

+0

@PascalCuoqええ、その特定の行のキャストは幾分かまわないですが、 'tfront = 255'のようなまれなケースでしか問題にならないでしょう。ゼロへのラップアラウンドは、符号なし変数に対しては明確に定義されているので、プログラマがその動作に依存するコードを書いた場合、 'tfront'が暗黙的に宣言されるため期待通りに動作しません。暗黙的なプロモーションに関連するバグや奇妙な問題は、常にそれだけです。プログラマは実際に何を意図していましたか?彼らは奇妙なことが起こると予想したのだろうか、それとも驚きとして彼らに来るのだろうか?そのような場合には、コードにコメントを付けることが非常に重要です。 – Lundin

関連する問題