あなたはこれを過度に複雑にしています。線形検索やテーブルに格納されたキーは必要ありません。あなたの値をレンジ・チェックし、それをテーブル・インデックスとして使用してください。
私はMASM構文を使用していると思いますので、これをMASM構文で記述しようとしますが、構文が間違っている可能性があります。しかし、実際の命令とロジックは正しいはずです。
section .rdata ; read-only data on Windows
CaseTable:
DWORD Process_A, Process_B ; function pointers
DWORD Process_C, Process_D
NumberOfEntries = ($ - CaseTable)/4
; optional: define constants for 'A' and 'D' and use those in the code below
; so the keys/values are still all in one place in the source.
.text ; or .code or something.
; You were missing a section directive between your data and code.
; input: selector in EAX
dispatcher: ; you were also missing a label for your function
; movzx eax, al ; if your selector really was just a byte
sub eax, 'A' ; convert to idx. values below 'A' wrap to high unsigned
cmp eax, 'D' - 'A' ; NumberOfEntries
ja @Default ; unsigned compare rejects out-of-range high or low
call [CaseTable + eax*4]
; then fall through. Use jmp as a tail-call if you don't want that.
@Default:
ret
素敵な(かつ効率的)ASMを書き込むトリックはそれが本当にどのようにシンプルに問題を通じて確認することです。あなたのキーがすべて連続した値であるような特別な状況を手動で利用する必要があります。あなたはコンパイラです。 :)
関数ポインタは
Process_A:
mov eax, [esp+4] ; return first arg unchanged
ret
Process_B:
mov eax, [esp+4]
add eax, eax ; return n * 2
ret
Process_C:
mov eax, [esp+4]
lea eax, [eax + eax*2] ; return n * 3
ret
Process_D:
mov eax, [esp+4]
shl eax, 2 ; return n * 4
ret
もちろん、あなたがちょうど1からの未知の数で乗算するimul
を使用したい、このためにディスパッチテーブルを使用することはありませんように、他の機能を指している必要があります4.これは単なる例です。
コンパイラはswitch
/case
文を最適化するためのクールなトリックをたくさん知っています。ケースラベルの多くは並行して、それらのいずれかの場合をテストするために同じことを、打ち鳴らすとgcc will use an immediate bitmapを行うときに私のお気に入りの一つは次のとおりです。
void errhandler(enum errtype numError) {
switch (numError) {
case ERROR_01 : // intentional fall-through
case ERROR_07 : // intentional fall-through
case ERROR_0A : // intentional fall-through
case ERROR_10 : // intentional fall-through
case ERROR_15 : // intentional fall-through
case ERROR_16 : // intentional fall-through
//case ERROR_20 : // keep the range of cases smaller for simpler 32-bit code
fire_special_event();
break;
default:
// error codes that require no additional action
break;
}
}
は次のように(clang4.0.1 -O3 -m32
on the Godbolt compiler explorer)
errhandler(errtype): # @errhandler(errtype)
mov eax, dword ptr [esp + 4] # load first function arg
cmp eax, 22
ja .LBB0_2
mov ecx, 6358146 # 0x610482 is a bitmap of those error codes
bt ecx, eax
jae .LBB0_2 # aka JNC: jump if CF=0, i.e. the bit wasn't set, i.e. ((1<<eax) & ecx) was false
jmp fire_special_event() # TAILCALL
.LBB0_2:
ret
をコードにコンパイル
残念ながら、コンパイラは、条件付きの末尾呼び出しとしてJCCを使用するのに十分にスマートではないので、代わりに彼らは条件付きでjmp
を飛び越える:/
gccがの使用を選択しますbt
を使用する代わりに、bt
を使用する代わりに、0/shl
を使用することをお勧めします。/
なぜこのタグは 'java'ですか? – chrylis
教授や先生の助手に相談してください。 –
_ "しかし、このコードは不完全で、私自身のケーステーブルを構築するためにどのように使用するのかわかりません" _ - 教科書やクラスノートに戻り、教授と話をする時間です。私たちはあなたのために仕事をするつもりはありません。 –