データ型の選択
データを効率的に処理するため、使用するデータ型や最も効率的な変数配置を検討する必要があります。
効率的なデータ型の使用
使用するデータ型は、コードのサイズや速度に大きく影響することがあるため、慎重に検討する必要があります。
可能な限り
charやshortの代わりにintまたはlongを使用して、符号拡張やゼロ拡張を回避します。特に、ループのインデックスは、コード生成を最小に抑えるため、必ずintまたはlongにしてください。また、Thumbモードでは、スタックポインタ(SP)を介したアクセスは、32ビットデータ型に制限されます。これにより、このようなデータ型を使用するメリットを利用できます。アプリケーションで符号付き値が必要でない限り、符号なしデータ型を使用してください。
32ビットモードでは、64ビットデータ型(
doubleやlong longなど)を使用する際のコストに注意してください。数値演算コプロセッサのないマイクロプロセッサで浮動小数点数型を使用すると、コードサイズと実行速度の両面で効率が低下します。
const型データへのポインタを宣言すると、参照先のデータが変化しないことが呼び出し元関数に通知され、最適化の向上につながります。
サポートされているデータ型、ポインタ、構造体の表現の詳細は、「データ表現」を参照してください。
浮動小数点数型
数値演算コプロセッサのないマイクロプロセッサで浮動小数点数型を使用すると、コードサイズと実行速度の両面で効率が低下します。そのため、浮動小数点数演算を使用するコードを、整数演算を使用するコードに置き換えることを検討してください。これにより効率が向上します。
コンパイラは、3種類(16、32、64ビット)の浮動小数点数フォーマットをサポートしています。32ビット浮動小数点数型のfloatの方は、コードサイズと実行速度の両面において効率が優れます。64ビットフォーマットのdoubleは、より高い精度とより大きな数値に対応します。16 ビットフォーマットは一部の特定の状況で役立ちます。
このコンパイラでは、float浮動小数点数型は常に32ビットフォーマットを使用し、double型は常に64ビットフォーマットを使用します。
アプリケーションが 64 ビット浮動小数点数による高精度を必要としない限り、32 ビット浮動小数点数の使用の使用をお勧めします。
デフォルトでは、ソースコード内の浮動小数点定数は、double型として扱われます。このため、何でもないような式が倍精度で評価される可能性があります。以下の例では、aがfloatからdoubleに変換され、double定数1.0を加えた後、その結果が再度floatに変換されます。
double Test(float a)
{
return a + 1.0;
}浮動小数点定数をdoubleではなくfloatとして扱うには、以下の例のようにfを追加します。
double Test(float a)
{
return a + 1.0f;
}不動小数点型の詳細については、基本データ型浮動小数点数型を参照してください。
構造体要素のアライメント
Armコアによっては、メモリ内のデータにアクセスする際に、データがアラインメントされている必要があります。 構造体の各要素は、指定した型の要件に応じてアライメントされている必要があります。つまり、コンパイラは、正しいアライメントを保守するため、パディングバイトを挿入しなければならないことがあります。
これが問題になりうる状況があります。
外部要件。たとえば、ネットワーク通信プロトコルは通常、間にパディングのないデータ型に関して指定されます。
データメモリを節約する必要がある場合。
アライメントの要件については、アライメントを参照してください。
構造体のレイアウトをより密にするために#pragma packディレクティブまたは__packedデータ型属性を使用します。欠点は構造体のアライメントされていない要素にアクセスするたびにコードが使用されることです。
または構造体のパック/アンパック用のユーザカスタム関数を記述する。 こちらの方が移植性が高く、ユーザカスタム関数以外の追加コードは生成されません。欠点として、構造体のデータをパックとアンパックの2つの状態で確認する必要があります。
#pragma packディレクティブの詳細は、packを参照してください。
無名構造体と無名共用体
構造体や共用体を名前なしで宣言すると、それらは匿名になります。その結果、それらのメンバは前後のスコープでのみ認識されます。
例
以下の例では、匿名のunionのメンバに、union名を明示的に指定せずに、関数Fでアクセスできます。
struct S
{
char mTag;
union
{
long mL;
float mF;
};
} St;void F(void)
{
St.mL = 5;
}メンバ名は、その前後のスコープ内で固有なものであることが必要です。匿名のstruct/unionを、ファイルスコープレベルで、グローバル変数、外部変数、静的変数のいずれかとして使用することもできます。これは、以下の例のように、I/Oレジスタの宣言などに使用できます。
__no_init volatile
union
{
unsigned char IOPORT;
struct
{
unsigned char way: 1;
unsigned char out: 1;
};
} @ 0x1000;
/* The variables are used here. */
void Test(void)
{
IOPORT = 0;
way = 1;
out = 1;
}この例は、I/OレジスタバイトIOPORTをアドレス0x1000に宣言します。I/Oレジスタには2ビットの宣言があり、WayとOutで、内部の構造体と外部の共用体のいずれも匿名になっています。
匿名の構造体や共用体はオブジェクトとして実装されます。このオブジェクトの名前は、最初のフィールドにプレフィックス_A_を付けた名前となり、名前空間の実装部で配置されます。この例では、無名共用体は_A_IOPORTというオブジェクトを使用して実装されます。