6

私は次のCコードを持っています:

#define PRR_SCALE 255
...
uint8_t a = 3;
uint8_t b = 4;
uint8_t prr;
prr = (PRR_SCALE * a) / b;
printf("prr: %u\n", prr);

これをコンパイルすると(msp430プラットフォームコンパイラを使用して、contikiと呼ばれる小さな組み込みOSの場合)、結果は0になりますが、191を期待していました(uint8_tはunsigned charとしてtypedefされています)

次のように変更した場合:

uint8_t a = 3;
uint8_t b = 4;
uint8_t c = 255;
uint8_t prr;
prr = (c * a) / b;
printf("prr: %u\n", prr);

正しく動作し、191を出力します。

Ubuntuボックスでgccを使用してこの「通常」の単純なバージョンをコンパイルすると、どちらの場合も正しい値が出力されます。

これがなぜなのか正確にはわかりません。事前にDEFINEd値を変数に割り当てることで回避できますが、そうはしません。

なぜこれなのか誰か知っていますか?おそらく、これに関するいくつかの詳細情報へのリンクがありますか?

4

5 に答える 5

10

簡単な答え:あなたのコンパイラはバグがあります。(他の人が示唆しているように、オーバーフローの問題はありません。)

どちらの場合も、算術演算はで行われint、少なくとも16ビット長であることが保証されています。前者のスニペットで255は、intであるためです。後者では、汎整数拡張のためです。

お気づきのとおり、gccはこれを正しく処理します。

于 2009-04-26T22:03:08.633 に答える
2

255は整数リテラルとして処理されており、式全体がunsignedcharベースではなくintベースになります。2番目のケースでは、タイプが正しくなります。次のように#defineを変更してみてください。

 #define PRR_SCALE ((uint8_t) 255)
于 2009-04-26T21:33:15.320 に答える
2

問題のコンパイラがmspgccの場合、コンパイルされたプログラムのアセンブラリストをbinary/hexファイルと一緒に出力する必要があります。他のコンパイラは、そうするために追加のコンパイラフラグを必要とする場合があります。または、別の逆アセンブラでさえバイナリで実行されます。

説明を探す場所です。コンパイラの最適化により、プロセッサに提示される実際のコードは、元のCコードとあまり類似していない可能性があります(ただし、通常は同じ仕事をします)。

障害のあるコードを表すいくつかのアセンブラ命令をステップスルーすると、問題の原因が明らかになるはずです。

私の推測では、コンパイラは計算全体を何らかの形で最適化します。定義された定数はコンパイル時に既知の部分です。255*xはx<<8-x(より高速で小さい)に最適化できます。最適化されたアセンブラーコードに問題がある可能性があります。

私は自分のシステムで両方のバージョンをコンパイルするのに時間をかけました。アクティブな最適化を使用すると、mspgccは次のコードを生成します。

#define PRR_SCALE 255
uint8_t a = 3;
uint8_t b = 4;
uint8_t prr;
prr = (PRR_SCALE * a) / b;
    40ce:   3c 40 fd ff     mov #-3,    r12 ;#0xfffd
    40d2:   2a 42           mov #4, r10 ;r2 As==10
    40d4:   b0 12 fa 6f     call    __divmodhi4 ;#0x6ffa
    40d8:   0f 4c           mov r12,    r15 ;
printf("prr: %u\n", prr);
    40da:   7f f3           and.b   #-1,    r15 ;r3 As==11
    40dc:   0f 12           push    r15     ;
    40de:   30 12 c0 40     push    #16576      ;#0x40c0
    40e2:   b0 12 9c 67     call    printf      ;#0x679c
    40e6:   21 52           add #4, r1  ;r2 As==10

ご覧のとおり、コンパイラは255 * 3から-3(0xfffd)の結果を直接計算します。そしてここに問題があります。どういうわけか、255は255の符号なし16ビットではなく-1の符号付き8ビットとして解釈されます。または、最初に8ビットに解析されてから、16ビットに符号拡張されます。または何でも。

このトピックに関する議論は、mspgccメーリングリストですでに開始されています。

于 2009-04-29T11:47:36.653 に答える
1

定義が機能しない理由はわかりませんが、uint8_t変数を使用してロールオーバーが発生している可能性があります。255はの最大値であるためuint8_t (2^8 - 1)、これに3を掛けると、いくつかの微妙なロールオーバーの問題が発生することになります。

コンパイラーは、コードを最適化し、数式の結果を事前に計算し、結果をprrに表示している可能性があります(中間値が適合しない場合でも、適合しているため)。

このように式を分割するとどうなるかを確認してください(これは希望どおりに動作しません)。

prr = c * a; // rollover!
prr = prr / b;

より大きなデータ型を使用する必要があるかもしれません。

于 2009-04-26T21:48:16.780 に答える
0

ケース1で考えられる違いの1つは、

PRR_SCALEリテラル値は、ROMまたはコード領域に入る可能性があります。また、MULオペコードにはいくつかの違いがあるかもしれません。

case-1: [register], [rom]
case -2: [register], [register]

まったく意味がないかもしれません。

于 2009-04-27T07:15:46.353 に答える