最近學習WP8.1應用開發,想把C語言的SM3國密算法移植到手機app中。因爲把C語言的代碼轉換成C#代碼工做量較大,所以只能用winodws運行時組件來實現。算法
SM3國密算法是一種HASH算法,具體詳情請自行百度。windows
結果測試發現手機上SM3算法計算出來的結果和電腦上運行的結果不一樣!通過我一點點調試發現是位移操做惹的禍,代碼中有以下宏定義:app
#define SHL(x,n) (((x) & 0xFFFFFFFF) << n) #define ROTL(x,n) (SHL((x),n) | ((x) >> (32 - n)))
第一行的宏定義當n大於32時,手機運算結果與電腦不一樣;第二行的宏定義當32-n小於0時,手機運算結果與電腦不一樣。函數
爲了更好地測試,我決定建一個乾淨的測試環境。首先新建一個C#語言的空白的windows phone應用項目,在xaml中放一個textblock和2個按鈕學習
<Grid> <StackPanel> <TextBlock x:Name="txbResult"/> <Button x:Name="btnCSharpLeft" Content="C#位移" Click="btnCSharpLeft_Click"></Button> <Button x:Name="btnCLeft" Content="C左位移" Click="btnCLeft_Click"></Button> </StackPanel> </Grid>
再實現按鈕點擊事件測試
private void btnCSharpLeft_Click(object sender, RoutedEventArgs e) { txbResult.Text += "C#位移\n"; for (int i = 0; i < 96; i += 8) { string str = "0x12345678<<" + i.ToString() + "=" + (0x12345678 << i).ToString("X"); txbResult.Text += str.PadRight(40) + "0x12345678>>" + i.ToString() + "=" + (0x12345678 >> i).ToString("X") + "\n"; } } private void btnCLeft_Click(object sender, RoutedEventArgs e) { txbResult.Text += "C位移\n"; Class1 c = new Class1(); for (int i = 0; i < 96; i += 8) { string str = "0x12345678<<" + i.ToString() + "=" + c.Func2(0x12345678, i).ToString("X"); txbResult.Text += str.PadRight(40) + "0x12345678>>" + i.ToString() + "=" + c.Func1(0x12345678, i).ToString("X") + "\n"; } }
接着新建一個C++語言的windows運行時組件,對外提供兩個函數,用以實現左位移和右位移spa
unsigned int Class1::Func1(unsigned int n, int b) { return n >> b; } unsigned int Class1::Func2(unsigned int n, int b) { return n << b; }
而後連上手機進行測試,個人手機是nokia920,公司測試部的測試機,先拿來用用,吼吼!
調試
能夠看到C#的位移在超過32時是對32取模的,也就是說位移33位至關於位移1位,而手機上運行結果測試超過32位都是0!code
爲了肯定是否C++語言的位移都是這麼處理的,我再新建一個WIN32的控制檯項目來測試blog
#include "stdio.h" int main() { printf("C左移\n"); for (int i = 0; i < 96; i += 8) { printf("0x12345678<<%d = %x\n",i,0x12345678 << i); } printf("C右移\n"); for (int i = 0; i < 96; i += 8) { printf("0x12345678>>%d = %x\n", i, 0x12345678 >> i); } return 0; }
運行結果以下
能夠看到和C#的結果是同樣的。說明只有C++的windows運行時組件中才會有不一樣的結果。
同理我再測試位移負數位,好比 0x12345678>>-2,在C#和C++的WIN32程序中位移-2位至關於位移30位,而在C++的windows運行時組件中則結果是0。
結論:爲了兼容性,位移時要對32取模,好比1>>n要寫成1>>(n%32),這樣在不一樣的平臺中也能獲得相同的結果。