あなたの最善の策は、比較と関連するアクション/ブランチのようなフラグの使用法を探すことです。タイプに応じて、コンパイラは異なるコードを生成します。ほとんどの (関連する) アーキテクチャは、符号付きの値を処理するためのフラグを提供します。x86 を例にとると、次のようになります。
jg, jge, jl, jle = branch based on a signed comparison (They check for the SF flag)
ja, jae, jb, jbe = branch based on a unsigned comparison (They check for the CF flag)
最近では 2 の補数表現を使用しているため、CPU のほとんどの命令は、符号付き/符号なし演算で同じになります。しかし、例外があります。
例として右シフトを考えてみましょう。X86 で符号なしの値を使用すると、SHR を使用して何かを右にシフトします。これにより、左側のすべての「新しく作成されたビット」にゼロが追加されます。
ただし、符号付きの値の場合、通常は SAR が使用されます。これは、MSB がすべての新しいビットに拡張されるためです。これは「符号拡張」と呼ばれ、2 の補数を使用しているためにのみ機能します。
最後になりましたが、符号付き/符号なしの乗算/除算にはさまざまな命令があります。
idiv or one-operand imul = signed
div or mul/mulx = unsigned
コメントに記載されているようにimul
、2 つまたは 3 つのオペランドを使用しても何も意味しません。imul
上位半分の結果を書くのに時間を無駄にしない形式でのみ存在するため、コンパイラ (および人間) は、特に上位半分の結果が必要な場合 (最適化など) を除いて、符号の有無に関係なく を使用imul
uint64_t = u32 * (uint64_t)u32
します。唯一の違いは、特にコンパイラによって生成されたコードではめったに見られないフラグが設定されていることです。
また、NEG 命令は通常、2 の補数の否定であるため、符号付きの値でのみ使用されます。( の一部として使用された場合abs()
、結果は INT_MIN でのオーバーフローを避けるために符号なしと見なされる場合があります。)