C プログラミングと error_code 変数の効率
-
11-09-2019 - |
質問
私がこれまで読んだコードのほとんどは、 int
標準エラー処理 (関数からの戻り値など) 用。しかし、それを使用することで何かメリットがあるのか疑問に思っています。 uint_8
コンパイラは次のように読み取ります:ほとんどのアーキテクチャ上のほとんどの C コンパイラは、即時アドレス モードを使用して命令を生成します。つまり、1 バイトの整数を命令に埋め込みます。私が考えている重要な命令は、戻り値の型として uint_8 を使用する関数が戻った後の比較です。
1 バイト型を導入するとアライメントの問題が発生するだけなので、私は物事を間違って考えている可能性があります -- コンパイルが物事を 4 バイトに詰めたがるのにはおそらく完全にまともな理由があり、これがおそらく誰もが int を使用する理由です -- そしてこれはヒープではなくスタック関連の問題であるため、実際のオーバーヘッドはありません。
正しいことをすることが私が考えていることです。しかし、議論のために、これがインテリジェント時計用の人気のある安価なマイクロプロセッサであり、1kのメモリで構成されているが、その命令セットには異なるアドレッシングモードがあるとしましょう:D
議論 (x86) を少し特殊化した別の質問は次のとおりです。は次のリテラルです:
uint_32 x=func(); x==1;
そして
uint_8 x=func(); x==1;
同じタイプですか?または、2 番目の場合、コンパイラーは 8 バイトのリテラルを生成します。存在する場合、それを使用して、リテラルを即値として、返された int をレジスタ参照として持つ比較命令を生成できます。 CMP 命令タイプを参照してください。.
解決
ここに1つの特定のコンパイラは、次のコードのために何をするかです。
extern int foo(void) ;
void bar(void)
{
if(foo() == 31) { //error code 31
do_something();
} else {
do_somehing_else();
}
}
0: 55 push %ebp
1: 89 e5 mov %esp,%ebp
3: 83 ec 08 sub $0x8,%esp
6: e8 fc ff ff ff call 7 <bar+0x7>
b: 83 f8 1f cmp $0x1f,%eax
e: 74 08 je 18 <bar+0x18>
10: c9 leave
11: e9 fc ff ff ff jmp 12 <bar+0x12>
16: 89 f6 mov %esi,%esi
18: c9 leave
19: e9 fc ff ff ff jmp 1a <bar+0x1a>
CMPの3バイト命令。 fooは()文字を返す場合、我々が得ます B:図3c 1F CMP $から0x1f、%のAl
あなたがが、効率を探しているなら。 %A1のものを比較すると、%eaxに
と比較してより高速であると仮定しないでください。他のヒント
特定のアーキテクチャ上の異なる整数型の間に非常に小さな速度差があるかもしれません。しかし、あなたは、あなたが別のハードウェアに移動した場合、それは変更される可能性があり、それに頼ることはできない、とあなたは、新しいハードウェアにアップグレードする場合はそれも遅くなることがあります。
そして、あなたは、あなたが与えている例でのx86について話す場合は、falseを仮定します:タイプuint8_t
であることが当面のニーズを。
は、実際の命令に埋め込まれた8ビットの即値は、C表記で、タイプint8_t
のものであり、バイト、ワード、ダブルワード及びqwordsで使用することができる:char
、short
、int
及びlong long
だから、このアーキテクチャでは何も全く利益、コードサイズや実行速度のいずれもないでしょう。
計算には int 型または unsigned int 型を使用する必要があります。複合体 (構造体/配列) のみに小さい型を使用します。その理由は、通常、int はプロセッサにとって「最も自然な」整数型として定義されており、他のすべての派生型は正しく動作するために処理が必要になる可能性があるためです。Solaris for SPARC 上の gcc でコンパイルしたプロジェクトでは、8 ビット変数と 16 ビット変数にアクセスする場合に命令がコードに追加されました。メモリから小さい型をロードする場合、レジスタの上部が適切に設定されていることを確認する必要がありました (符号付き型の場合は符号拡張、符号なしの場合は 0)。これによりコードが長くなり、レジスタへの負荷が増大し、他の最適化が悪化しました。
具体的な例があります。
構造体の 2 つの変数を uint8_t として宣言し、そのコードを Sparc Asm に取得しました。
if(p->BQ > p->AQ)
に翻訳されました
ldub [%l1+165], %o5 ! <variable>.BQ,
ldub [%l1+166], %g5 ! <variable>.AQ,
and %o5, 0xff, %g4 ! <variable>.BQ, <variable>.BQ
and %g5, 0xff, %l0 ! <variable>.AQ, <variable>.AQ
cmp %g4, %l0 ! <variable>.BQ, <variable>.AQ
bleu,a,pt %icc, .LL586 !
そして、これが2つの変数をuint_tとして宣言したときに得られたものです
lduw [%l1+168], %g1 ! <variable>.BQ,
lduw [%l1+172], %g4 ! <variable>.AQ,
cmp %g1, %g4 ! <variable>.BQ, <variable>.AQ
bleu,a,pt %icc, .LL587 !
算術演算が 2 つ減り、その他のレジスターが 2 つ増えます
プロセッサは、一般的にCで「int型」である彼らの自然なレジスタのサイズ、で作業するのが好き。
例外はありますが、あなたが存在しない問題にあまりを考えている。