單色位圖(1 bit per pixel)、硬體暫存器位欄位、通訊協議位流解析等,需從一個 uint8_t 讀取第 pos 位(0~7)的值(0 或 1)。
int byte8_2_int(char a, char pos) { // a: 目標位元組, pos: 位位置(0-7)
char reti = 0;
__asm {
mov al, a ; 載入位元組到 AL
mov cl, pos ; CL = 位位置
shr al, cl ; 邏輯右移 CL 位,目標位移至 LSB
and al, 0x01 ; 只保留 LSB
cmp al, 0x00
jnz set1 ; 若為 1 跳轉
jmp A_Exit ; 為 0 直接返回 reti(=0)
set1:
xor ax, ax ; 清零 AX
mov al, 0x01 ; AL = 1
mov reti, al ; 存回返回值
}
A_Exit:
return reti;
}
| 指令 | 作用 | 旗標影響 |
|---|---|---|
mov al, a | 將參數 a 載入 8 位暫存器 AL | 無 |
mov cl, pos | 將 pos 載入 CL(x86 移位指令隱含使用 CL 作為計數) | 無 |
shr al, cl | 邏輯右移 AL,高位補 0,目標位移至第 0 位 | CF=移出位,ZF/SF/PF 按結果更新 |
and al, 0x01 | 只保留第 0 位,AL 變 0 或 1 | ZF=1 若結果 0,CF=0 |
cmp al, 0 | 比較 AL 與 0,實際上 and 已設 ZF,此指令冗餘 | 同 and |
jnz set1 | ZF=0(結果非零)跳轉 | - |
jmp A_Exit | 無條件跳轉結束 | - |
set1: xor ax,ax | 清零 AX(含 AH/AL) | ZF=1 |
mov al, 1 | 設 AL=1 | ZF=0 |
mov reti, al | 存回 C 變數 | - |
static inline int byte8_2_int_c(uint8_t byte, unsigned pos) {
return (byte >> pos) & 1u;
}
shr + and 或 bt + setc)。static inline 消除呼叫開銷。// GCC/Clang
static inline int byte8_2_int_builtin(uint8_t byte, unsigned pos) {
return __builtin_bit_test((unsigned long long)byte, pos);
}
// MSVC
#include <intrin.h>
#pragma intrinsic(_bittest)
static inline int byte8_2_int_msvc(uint8_t byte, unsigned pos) {
return _bittest((long *)&byte, pos);
}
// 讀取 64 個位元組的第 3 位,生成 64 個 0/1 位元組
void extract_bit3_avx2(const uint8_t *src, uint8_t *dst, size_t n) {
__m256i mask = _mm256_set1_epi8(1 << 3);
for (size_t i = 0; i < n; i += 32) {
__m256i v = _mm256_loadu_si256((const __m256i*)(src + i));
__m256i res = _mm256_and_si256(v, mask);
res = _mm256_cmpeq_epi8(res, mask); // 0xFF/0x00
res = _mm256_and_si256(res, _mm256_set1_epi8(1)); // 1/0
_mm256_storeu_si256((__m256i*)(dst + i), res);
}
}
char 帶號問題:shr 對帶號 char 仍做邏輯右移(x86 無算術右移 8 位指令),但 C 語言 char 正負實作定義,建議統一用 uint8_t。pos 範圍未檢查:若 pos >= 8,x86 shr al, cl 只取 CL 低 5 位(模 32),行為與預期不符。應加 assert(pos < 8) 或 pos &= 7。__asm { ... },GCC/Clang 用 __asm__ volatile("..." : : : ),跨平台專案避免直接寫組語。int 但實際只用 0/1,建議改 bool 或 uint8_t 明確語意。#include <stdio.h>
#include <stdint.h>
#include <assert.h>
int main(void) {
uint8_t test = 0b10101100; // 0xAC
for (int p = 0; p < 8; ++p) {
int expected = (test >> p) & 1;
int asm_result = byte8_2_int(test, p);
int c_result = byte8_2_int_c(test, p);
printf("bit %d: asm=%d c=%d exp=%d %s\n",
p, asm_result, c_result, expected,
(asm_result == expected && c_result == expected) ? "OK" : "FAIL");
assert(asm_result == expected);
assert(c_result == expected);
}
puts("All tests passed.");
return 0;
}
雖然內嵌組語能精確控制指令流,但現代編譯器對位元操作優化極其成熟。優先使用標準 C 位運算(>>, &)配合 static inline,兼得可移植性、可讀性與極致效能。僅在編譯器無法生成特定指令(如 BIT 測試、CLZ、CRC 硬體加速)時,才以內建函式或內嵌組語補足。