《 C 語言的一些“騷操作”及其深層理解》之字節(jié)快速位逆序
字節(jié)快速位逆序
我給大家出一道有意思的題目:如何快速得到一個字節(jié)的位逆序字節(jié)。比如0X33的位逆序字節(jié)是0XCC。
有人給了我這樣一段代碼:
這段代碼很簡潔,也很巧妙。但是它卻不是最快的。后來作了改進:
這樣把循環(huán)打開,確實會提速不少。但它仍不是最快的實現(xiàn)方案。請看如下代碼:
恍然大悟了沒有?使用字節(jié)數(shù)組事先準備好位逆序字節(jié),然后直接以字節(jié)的值為下標索引,直接取數(shù)據(jù)即可。這種方法被稱為“空間換時間”。
這個問題我問過很多人,多數(shù)人并不能直接給出最佳方案。倒是有不少人問我這個問題有什么實際意義,為什么要去計算位逆序字節(jié)?請大家想想,如果我們把電路上的數(shù)據(jù)總線焊反或插反了該怎么解決。
關(guān)于volatile
現(xiàn)在的編譯器越來越智能,它們會對我們的代碼進行不同程度的優(yōu)化。請看下例:
unsigned char a;
a=1;
a=2;
a=3;
這樣一段代碼,有些編譯器會認為a=1與a=2根本就是毫無意義,會把它們優(yōu)化掉,只剩下a=3。但是,有些時候這段代碼是有特殊用途的:
unsigned charxdata a _at_ 0X1111;
a=1;
a=2;
a=3;
a不單單是一個變量,而是一個外部總線的端口(51平臺)。向它賦值會產(chǎn)生相應(yīng)的外部總線上的時序輸出,從而對外部器件實現(xiàn)控制。這種時候,a=1和a=2不能被優(yōu)化掉。舉個例子:a所指向的外部總線端口,是一個電機控制器的接口,向它寫入1是加速,寫入2是減速,寫入3是反向。那么上面的代碼就是加速->減速->反向,這樣一個控制過程。如果被優(yōu)化的話,那最后就只有反向了。
為了防止這種被“意外”倫的情況發(fā)生,我們可以在變量的定義上加一個修飾詞volatile。
volatile unsigned charxdata a _at_ 0X1111;
a=1;
a=2;
a=3;
這樣,編譯器就會對它單獨對待,不再優(yōu)化了。
volatile最常出現(xiàn)的地方,就是對芯片中寄存器的定義,比如STM32固件庫中有這樣的代碼:
#define __IO volatile
typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
} GPIO_TypeDef;
這是對STM32的GPIO寄存器組的定義,每一項都是一個__IO類型,其實就是volatile。這樣是為了對片內(nèi)外設(shè)的物理寄存器的訪問一定是真正落實的,而不是經(jīng)過編譯器優(yōu)化,而變成去訪問緩存之類的東西。