2013-05-14 12 views
26

C/C++で型キャスティングすると余分なCPUサイクルがかかるのですか?タイプキャスティングで余分なCPUサイクルが消費される

私の理解では、場合によっては少なくとも余分なCPUサイクルを消費する必要があります。 floatから整数への型キャストのように、CPUはfloat構造体を整数に変換する必要があります。

余分なCPUサイクルを消費する/しないケースを理解したいと思います。

+9

キャストの種類によって異なります。 –

+5

このC++をタグ付けしたので、私はC++スタイルのキャスト、つまり 'static_cast '、 'dynamic_cast '、 'reinterpret_cast '、 'const_cast 'の使用をお勧めします。 – JBL

+0

キャストが "フリー"であるかどうかにかかわらず、すべての言語関連の細部と細目を除外しても、おそらくプラットフォームによって大きく異なります。たとえば、x86では、より大きい種類から小さな種類へのほとんどの整数キャストは空きですが、これは特性の異なる別のプラットフォームでは当てはまりません。 – yzt

答えて

19

「タイプ間の変換」は、キャストがあるかどうかではなく、私たちが見なければならないものです。これはまた、例えば、型のサイズを変更することに適用

int a = 10; 
float b = (float)a; 

たとえば

int a = 10; 
float b = a; 

は同じになりますこれは潜在的に余分な命令を追加する(または余分なクロックサイクル(S)「[Cの意味ではなく、8ビットの感覚をバイトを使用して単一のバイトからintサイズにcを拡張」し

char c = 'a'; 
int b = c; 

使用されている命令への)データ移動そのものを超えて。

これらの変換はまったく明らかではないことに注意してください。 x86-64では、配列内のインデックスにunsigned intの代わりにintを使用しています。ポインタは64ビットなので、インデックスは64ビットに変換する必要があります。符号なしの場合、それは簡単です - 32ビットロード操作がレジスタの上部を0で埋めるので、値が既に入っているレジスタの64ビットバージョンを使用してください。しかし、intがあれば、それは否定的な可能性があります。だから、コンパイラは "これを64ビットに拡張する"命令を使わなければなりません。これは通常、固定ループに基づいてインデックスが計算され、すべての値が正の値である場合は問題ではありませんが、パラメータが正か負かを明確にしない関数を呼び出すと、コンパイラは必ず値を拡張する必要があります。同様に、関数がインデックスとして使用される値を返す場合も同様です。

しかし、合理的に能力のあるコンパイラは、何かを独自の型からそれ自身に変換するための命令を追加しません(最適化がオフになっている場合は可能ですが、最小限の最適化では "X型Xをタイプする、それは何も意味しない、それを取り除くことができる)。

つまり、上記の例では余計なペナルティは追加されませんが、「あるタイプから別のタイプへデータを変換すると、追加の命令やクロックサイクルがコードに追加されます」というケースがあります。
http://www.agner.org/optimize/
1:

+2

私の好きな区別のための+1:キャスト対コンバージョン。 –

+1

一般的な目的のレジスタでは、レジスタの一部にエイリアスがあるので、サイズを変更することは必ずしも問題ではありません...もちろん、それは可能です...しかし、スタック上でさえ、通常、符号なしの値のより大きなバージョンです。 –

+1

値を大きくすることには2つの問題があります。1.「上部」には何がありますか。2.上部には何がありますか。レジスタの上部にゼロが埋め込まれているため、x86-64の符号なしの値は設計上問題ありません。しかし、レジスタが符号拡張されていると想定されている場合は、符号が何であっても埋める必要があります。つまり、余分な命令が必要です。もちろん、上位32ビットが実際にあなたが望む値であるという保証は全くないので、スタックから64ビットを読み取ることはおそらくうまくいかないでしょう。 –

12

基本的な表現が変更されるサイクルを消費します。したがって、floatintまたはvice-viceに変換すると、サイクルが消費されます。 intcharまたはlong longintなどのアーキテクチャのキャストによっては、サイクルが消費される場合もあれば、消費されない場合もあります。ポインタ型間のキャストは、複数の継承が関係する場合にのみサイクルを消費します。

+2

ちょっとしたコメントです。 int to long longは、sizeof(long long)== sizeof(int)の場合にのみサイクルを消費すべきではありません。 – vishal

3

DLとはAgner霧のマニュアルをお楽しみください。C++での最適化ソフトウェア:Windows、Linux、およびMacのプラットフォームの最適化ガイド
それは巨大なPDFですが、スタートのためにあなたがチェックアウトすることができます:

14.7との間のfloatとdouble
14.8変換を混ぜて使用しないでください浮動小数点数と整数

7

さまざまなタイプのキャストがあります。 C++には、さまざまなタイプのキャストに異なるタイプのキャスト演算子があります。これらの用語で見れば、...

static_castは、通常、ターゲットタイプがソースタイプと異なるサイズの場合は、あるタイプから別のタイプに変換する場合にコストがかかります。 static_castは、ポインタを派生型から基本型にキャストするために使用されることがあります。これには、特に派生クラスが複数の基底を持つ場合には、コストがかかります。

reinterpret_cast通常、直接費用はありません。ゆるく言えば、このタイプのキャストは値を変更しないだけで、解釈方法を変更します。ただし、これには間接的なコストがある可能性があります。 intのポインタとしてバイト配列へのポインタを再解釈すると、そのポインタが参照されるまでポインタが参照されない限り、そのポインタを逆参照するたびにコストを支払うことがあります。

const_castは、constを追加または削除する場合は、ほとんどの場合、コンパイラの注釈であるため、費用はかかりません。揮発性修飾子を追加または削除する場合は、特定の最適化を有効または無効にするため、パフォーマンスの違いがあると思われます。

dynamic_castは、基本クラスへのポインタから派生クラスへのポインタへのキャストに使用されますが、変換が適切かどうかを最低限確認する必要があります。

伝統的なCキャストを使用する場合は、より具体的なキャストのタイプを選択するようにコンパイラに求めます。だから、あなたのCキャストにコストがあるかどうかを知るためには、実際にキャストのタイプを調べる必要があります。

+0

ええ、Cコードの場合は2つの質問になる必要があります。アセンブリレベルとC++コードの違いは、イニシャライザとテンプレートコードの実行を終了させる可能性があります。プログラマーの視点からは自動的です。 –

関連する問題