C言語:「=」の強制型変換
8052 ワード
前言:プログラムを書く時にいくつかのデータ型の変換に関する問題に出会って、コンパイラも間違っていないことを報告して、運行する時やっとデータが間違っていることを発見して、バグを探すのに多くの時間を費やして、しかし最終的にいくつかの細部の問題であることを発見して、わざわざここで1篇の文章の記録を整理します.
実験環境:チップアーキテクチャ:Cortex-M 0+ 開発IDE:Keil_v5 コンパイラ:armcc 質問コード:
計算 最後に結果を
シフトプログラムでは,右シフトデータに大きな問題はほとんどないが,左シフトには注意が必要である.32ビットマシンプラットフォームでは、8ビット、16ビット、32ビットのデータ型が32ビットレジスタでシフトされます.シフト後のデータが32ビットのデータ型を超えないことを確認すれば、プログラムは正常に動作します.一方、上記のデータ型がシフト後のデータ型が32ビットを超えると、プロセッサは左にシフトしたデータを失い、最低32ビットを残す.
問題解決:
実験環境:
質問コード: 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つのステップに分けることができる.
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));
一連の調査を経て、最終的に問題点を発見しました.主に以下の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));
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));