WP8.1中C++的winodws运行时组件位移操作的差异

  最近学习WP8.1应用开发,想把C语言的SM3国密算法移植到手机app中。由于把C语言的代码转换成C#代码工作量较大,因此只能用winodws运行时组件来实现。

  SM3国密算法是一种HASH算法,具体详情请自行百度。

  结果测试发现手机上SM3算法计算出来的结果和电脑上运行的结果不同!经过我一点点调试发现是位移操作惹的祸,代码中有如下宏定义:

#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运行时组件,对外提供两个函数,用以实现左位移和右位移

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!

为了确定是否C++语言的位移都是这么处理的,我再新建一个WIN32的控制台项目来测试

#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),这样在不同的平台中也能得到相同的结果。

 

posted on 2014-11-04 22:16  小小娟  阅读(1333)  评论(1编辑  收藏  举报

导航