首页 新闻 会员 周边

【高分邀请】对原码、反码、补码 理解深刻的同学帮我检查一段代,C#的

0
悬赏园豆:100 [已解决问题] 解决于 2014-01-07 16:35

补习了一下原码、反码、补码的知识,以为对它很懂了,可是遇到这个实际问题,还是不知道如何解决。这个问题困扰我很久了,高分邀请高手帮我看下这个需求和我的这小段代码。

【需求】:"ST 5101130010 TT 01052357 BV 141 P 0 RC 0 Z01 327 Q1 771144 SYL1 -3781330 Q2 0 SYL2 1000000 AQ1 4781330 AQ2 0 jmNN" 是一段接收到的报文字符串,具体意思大家不用深究,也是准确的,倒数三四个字符“jm”是该报文的验证码,如果根据验证码前面的字符串内容计算得出的校验码和jm校验码一致的话,表示验证通过。

【验证规则】:提取校验码前面的字符串内容进行校验。这些内容对应的所有字节累加,然后进行“补码”运算得到校验值。校验值字节拆为两个半字节并顺序填入两个字节的低位,变为2字节数据,再加上十六进制数6161H,则顺序得到二字节校验码,校验码对应的ASCII字符则为要和报文中比较的校验码一致。

【问题】:现在这条报文本身来说是没有问题的,我想我的问题还是出在累加求反的地方,但折腾了好久,还是没明白具体原因,生成的校验码和报文中的校验码始终不一致,求高手帮忙看一下,解决了还有分给啊,谢谢。

【我的代码如下】:

                    //  string strData = "ST DFSC0000 TT 11111111 Q1 300000 AQ1 30000000 SYL1 2500000 Q2 225 AQ2 625 SYL2 200 BV 136 SI 25 mbNN";
                    string strData = "ST 5101130010 TT 01052357 BV 141 P 0 RC 0 Z01 327 Q1 771144 SYL1 -3781330 Q2 0 SYL2 1000000 AQ1 4781330 AQ2 0 jmNN";

                    // 本报文字符串中倒数3、4位“jm”为校验码,如果和前面内容生成的校验码一致则表示验证通过。
                    string strVerifyCode = strData.Substring(strData.Length - 4, 2);
              
                    // 检验码前所有字节纵向累加后补运行得到校验值;
                    string strVerifyData = strData.Substring(0, strData.Length - 4);

                    // 待检验的字符串字节数据;
                    byte[] btsVerifyData = Encoding.ASCII.GetBytes(strVerifyData);
                   
                    // 累加待校验字节;
                    byte value = 0x00;
                    for (int i = 0; i < btsVerifyData.Length; i++)
                    {
                        value += btsVerifyData[i];
                    }

                    // 定义bt作为检验值,校验数据字节累加求补运算得到;
                    byte bt = 0x00;

                    // 通过value字节对象生成验证码,value字节最高位为符号位,> 0x80 (1000 0000)时, 符号位为0时表示为正,取原码值,为1时求补码;
                    bt = (value >= 0x80) ? (byte)~value: value;

                    // 将bt校验值字节拆为两个半字节顺序填入两个字节的低位;
                    byte[] btsCode = new byte[2];
                    btsCode[0] = (byte)(bt << 4);
                    btsCode[0] = (byte)(btCode[0] >> 4);
                    btsCode[1] = (byte)(bt >> 4);
        
                    // 两个字节加上61H,61H,得到二字节校验码;
                    btCode[0] += 0x61;
                    btCode[1] += 0x61;

                    string strCode = Encoding.ASCII.GetString(btCode);
                    if (strCode == strVerifyCode)
                    {
                        // OK,校验通过
                    }
                    else
                    {
                        // 校验失败
                    }

摩根鱼的主页 摩根鱼 | 初学一级 | 园豆:19
提问于:2014-01-07 14:44
< >
分享
最佳答案
0
for (int i = 0; i < btsVerifyData.Length; i++)
{
      value += btsVerifyData[i];
}

你这段代码可能存在溢出的问题,会不会是这里影响到了后面的运算?

你前面5个字符的ASCII值加起来已经超过255了,对超过的部分怎么处理?是只看低位还是需要高位?

=====================

又写了一下,用我自己的算法是完全可以的,最后输出的结果是True

            const string strData = "ST 5101130010 TT 01052357 BV 141 P 0 RC 0 Z01 327 Q1 771144 SYL1 -3781330 Q2 0 SYL2 1000000 AQ1 4781330 AQ2 0 jmNN";
            string strVerifyCode = strData.Substring(strData.Length - 4, 2);
            //Console.WriteLine(strVerifyCode);
            
            string strVerifyData = strData.Substring(0, strData.Length - 4);
            //Console.WriteLine(strVerifyData);

            byte[] btsVerifyData = Encoding.ASCII.GetBytes(strVerifyData);
            
            byte value = 0x0;
            for (int i = 0; i < btsVerifyData.Length; i++)
            {
                value += btsVerifyData[i];
            }
            Console.WriteLine("累加结果:0x{0:X}",value);
            byte newvalue = (byte) ((~value) + 1);
            Console.WriteLine("取补码结果:0x{0:X}",newvalue);

            byte b1 = (byte)((newvalue & 0xF0)>>4);
            Console.WriteLine("第一个校验值:0x{0:X}",b1);
            byte b2 = (byte) (newvalue & 0x0F);
            Console.WriteLine("第二个校验值:0x{0:X}",b2);
            short nb1 = (short) (b1 + 0x6161);
            short nb2 = (short) (b2 + 0x6161);
            Console.WriteLine("加上0x6161后的值:0x{0:X} & 0x{1:X}",nb1,nb2);
            byte nnb1 = (byte) nb1;
            byte nnb2 = (byte) nb2;
            Console.WriteLine("{0},{1}",(char)nnb1,(char)nnb2);

            byte[] bt = new byte[2] {nnb1, nnb2};
            string sbt = Encoding.ASCII.GetString(bt);
            Console.WriteLine(sbt == strVerifyCode);

 ====================

又及:你的算法本身有问题

// 通过value字节对象生成验证码,value字节最高位为符号位,> 0x80 (1000 0000)时, 符号位为0时表示为正,取原码值,为1时求补码;
bt = (value >= 0x80) ? (byte)~value : value;

你理解错了,题目要求的是算出前面110个字符的ASCII码值的和之后直接取补码。

取补码运算很简单:取反+1=补码

因此你的这句话可以改为

bt = (byte)(~value+1);

后面的一段

// 将bt校验值字节拆为两个半字节顺序填入两个字节的低位;
byte[] btsCode = new byte[2];
btsCode[0] = (byte)(bt << 4);
btsCode[0] = (byte)(btsCode[0] >> 4);
btsCode[1] = (byte)(bt >> 4);

首先顺序错了,应该btsCode[0] = 0x9, btsCode[1]=0xC,你正好弄反了

其次,你的算法太复杂,取高位右移4位即可,取低位只要与上一个0x0F即可。

因此将你的这些语句改为

byte[] btsCode = new byte[2];
btsCode[0] = (byte)(bt >> 4);
btsCode[1] = (byte)(bt & 0x0F);

其他部分照旧。最后的结果是True

收获园豆:100
飞鸟_Asuka | 菜鸟二级 |园豆:209 | 2014-01-07 15:36

当中的那些变量定义和赋值可以直接写成

byte[] btsCode = { (byte)(((byte)(~value + 1) >> 4) + 0x61), (byte)(((byte)(~value + 1) & 0x0F) + 0x61) };

简洁明快

飞鸟_Asuka | 园豆:209 (菜鸟二级) | 2014-01-07 16:40

@飞鸟_Asuka: 有一点点没明白,飞鸟,

1、前面累加溢出应该是只看低位字节的结果,因为value本身也被我定义成了byte型,或者定义成int或long型,最后求一个要计算的字节时也要 %256。

1、~我看到网上说的是个取补运算符,,还举了java中的例子,int a = 6,~6取补就成了-7,我在C#中也验证过,所以一直以为~就是取补运算。那现在看来~是取反,但是如果value字节第一位是0,表示正的话,求补码不是就不应该加1么?

2、就是补码结果放入两个字节低位的顺序,按照我的理解,就应该是字节低四位放到第0个字节的低位,高四位放到第二个字节的低位,所以,也犯了错,你的结果是正确的,但是为什么是这样的理解呢。

摩根鱼 | 园豆:19 (初学一级) | 2014-01-08 09:05

@摩根鱼: 一个一个来啊

1、实践证明定义成byte即可,主要是后面被你的“+6161H”给误导了。

2、“~”运算符是按位取反,哪来的“取补”说法?因此网上的胡说不可信啊

int a = 6,也就是0110,取补码后就是1010,是-6而不是-7。

不过所谓“取补码”的说法本来就有争议,因为正数的补码是它的原码,负数的补码是它的相反数的原码取反+1。你之前的110个字符求和的结果是0x64是个正数,它的补码还是0x64。

从题目要求和具体实现上来看,不应该说是“取补码”而应该说“取负”。0x64的相反数的补码是0x9C

3、从你的题目上来看,实际上应该把0x9C的高4位和低4位分别放入两个字节的低4位,也就是变成0x090C,再加上0x6161变成0x6A6D,一字节一字节地看正好就是jm。但是在实际过程中把它变成分开的两个字节去运算也是没有问题的。

飞鸟_Asuka | 园豆:209 (菜鸟二级) | 2014-01-08 09:27

@摩根鱼: 刚试了一下,又发现果然把取反+1改成取负

byte new_value = (byte)-value;

也一样成立

飞鸟_Asuka | 园豆:209 (菜鸟二级) | 2014-01-08 14:00

@飞鸟_Asuka: 那这到底是个什么意思呢,就是说那个协议中的意思实际上是取负运算么?

摩根鱼 | 园豆:19 (初学一级) | 2014-01-09 17:39

@摩根鱼: 从实际效果来看是如此

但是究竟符不符合题意还是需要好好思考一下

飞鸟_Asuka | 园豆:209 (菜鸟二级) | 2014-01-09 19:26

飞鸟兄,我新发了一个Javascript数组的问题,麻烦你帮我看看啊

摩根鱼 | 园豆:19 (初学一级) | 2014-01-27 20:57

@摩根鱼: 不好意思,JS我水平不高的

飞鸟_Asuka | 园豆:209 (菜鸟二级) | 2014-01-27 21:08
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册