C言語:「=」の強制型変換

8052 ワード

前言:プログラムを書く時にいくつかのデータ型の変換に関する問題に出会って、コンパイラも間違っていないことを報告して、運行する時やっとデータが間違っていることを発見して、バグを探すのに多くの時間を費やして、しかし最終的にいくつかの細部の問題であることを発見して、わざわざここで1篇の文章の記録を整理します.
実験環境:
  • チップアーキテクチャ:Cortex-M 0+
  • 開発IDE:Keil_v5
  • コンパイラ:armcc
  • 質問コード:

    uint64_t TempData2;
    uint8_t  KeyeBuf1[8];
    TempData2 = ( KeyeBuf1[0]  + (KeyeBuf1[1] << 8) + (KeyeBuf1[2] << 16) + (KeyeBuf1[3] << 24)+ 
        (KeyeBuf1[4] << 32) + (KeyeBuf1[5] << 40) + (KeyeBuf1[6] << 48));
    

    上記のコードでは、TempData2のデータ型が符号なし64ビット整数型であることが以前に宣言されており、次のシフト後の累積データには常にエラーが発生し、累積後のデータ範囲も符号なし64ビット整数型データ範囲を超えていないことを確認する.

    問題の分析:


    一連の調査を経て、最終的に問題点を発見しました.主に以下の3つの面がもたらした影響です.

    1.マシンプラットフォームとコンパイラの影響


      stdint.hはC 99に導入された標準Cライブラリのファイルであり、現在、ほとんどのシングルチップマシンのCコンパイラがサポートされている.コンパイラ・ブランチに関するより多くのデータ型は、このファイルで完全に見つかります.armccコンパイラの例として、ファイルでは、8ビット、16ビット、32ビット、64ビットの符号なし整数タイプのデータを以下のように定義します.
    #include
    uint64_t TempData2;
    typedef unsigned          char uint8_t;
    typedef unsigned short     int uint16_t;
    typedef unsigned           int uint32_t;
    typedef unsigned       __INT64 uint64_t;
    

    ファイルを検索するとuint 64_tのタイプはunsigned_INT 64タイプ、_INT 64型の解釈は、マシンプラットフォームおよびコンパイラに関連している.機器プラットフォームのハードウェアアーキテクチャおよびコンパイラのコンパイルは、最終的に実行コードの生成に影響します.Cortex-M 0+は32ビットのプロセッサで、内部のレジスタの多くは32ビットであるため、デフォルトで行われる演算は、8ビット、16ビット、32ビットにかかわらず32ビットレジスタで演算される.

    2.「=」記号の演算順序の影響


      =符号の実行プロセスは、細分化されて2つのステップに分けることができる.
  • 計算=右側部分最終結果
  • 最後に結果を=に付与左変数そして計算を行います.

  • 3.シフトプログラム移植性の影響


      シフトプログラムでは,右シフトデータに大きな問題はほとんどないが,左シフトには注意が必要である.32ビットマシンプラットフォームでは、8ビット、16ビット、32ビットのデータ型が32ビットレジスタでシフトされます.シフト後のデータが32ビットのデータ型を超えないことを確認すれば、プログラムは正常に動作します.一方、上記のデータ型がシフト後のデータ型が32ビットを超えると、プロセッサは左にシフトしたデータを失い、最低32ビットを残す.

    問題解決:


      上記コードを解析すると、==配列のデータ型はいずれも8ビットであり、計算時は32ビットレジスタで計算される.最初のデータのシフトが32ビットを超えていないデータ型は大きな誤りはなく、( KeyeBuf1[0] + (KeyeBuf1[1] << 8) + (KeyeBuf1[2] << 16) + (KeyeBuf1[3] << 24)+ (KeyeBuf1[4] << 32) + (KeyeBuf1[5] << 40) + (KeyeBuf1[6] << 48));から理論的にシフトしたデータが32ビットを超え、最低32ビットしか残っておらず、データエラーを招く.最後に64ビットの変数を割り当てても、32ビットのデータを64ビットに割り当てますが、これらの問題はコンパイラがコンパイル中に指摘しないので、自分で注意する必要があります.  最後の解決策は、Keye1データを演算時に強制的に64ビットデータ型に変換することであり、演算時に64ビットデータが整列し、最後に64ビットデータ型が付与され、データ損失は発生しない.コードは次のとおりです.
     TempData2 = ( KeyeBuf1[0]  + (KeyeBuf1[1] << 8) + (KeyeBuf1[2] << 16) + ((uint64_t)KeyeBuf1[3] << 24)+ 
       ((uint64_t)KeyeBuf1[4] << 32) + ((uint64_t)KeyeBuf1[5] << 40) + ((uint64_t)KeyeBuf1[6] << 48));