a^=b^=a^=b的Bug?

  这段代码
int a = 100, b = 7;
a^=b^=a^=b;
Console.WriteLine(a + " " + b);
  的 作用 意图应该是交换两个整数,然而运行结果出乎意料:
0 100
  而
a ^= b;
b ^= a;
a ^= b;
  正确地交换了a和b。在VS.NET 2003和VS 2005 Beta2中的C#运行结果一样。 经检查,所生成的IL代码没有问题: 怪我没有仔细看,IL代码与最后所生成的汇编代码一致。单击这里见思归的详细分析
      L_0000: ldc.i4.s 100
      L_0002: stloc.0
      L_0003: ldc.i4.7
      L_0004: stloc.1
      L_0005: ldloc.0
      L_0006: ldloc.1
      L_0007: ldloc.0
      L_0008: ldloc.1
      L_0009: xor
      L_000a: dup
      L_000b: stloc.0
      L_000c: xor
      L_000d: dup
      L_000e: stloc.1
      L_000f: xor
      L_0010: stloc.0
      L_0011: ldloc.0
      L_0012: box int32
      L_0017: ldstr " "
      L_001c: ldloc.1
      L_001d: box int32
      L_0022: call string string::Concat(object, object, object)
      L_0027: call void [mscorlib]System.Console::WriteLine(string)
      L_002c: ret
   但是 最后生成的汇编 却有问题
    1:   int a = 100, b = 7;
00000000  push        ebp 
00000001  mov         ebp,esp
00000003  sub         esp,18h
00000006  push        edi 
00000007  push        esi 
00000008  push        ebx 
00000009  xor         edi,edi
0000000b  xor         ebx,ebx
0000000d  mov         edi,64h
00000012  mov         ebx,7

    2:   a ^= b;
00000017  xor         edi,ebx
    3:   b ^= a;
00000019  xor         ebx,edi
    4:   a ^= b;
0000001b  xor         edi,ebx
    5:   a^=b^=a^=b;
0000005e  mov         esi,edi
00000060  xor         edi,ebx
00000062  xor         ebx,edi
00000064  xor         esi,ebx
00000066  mov         edi,esi

  这是个Bug吗?最初我认为是这样的,而且还把这个“Bug”提交到了MSDN Product Feedback Center。但思归给出的C# Language Specification, 14.2让我如梦方醒。全文在这里 不过 在反馈中心得到的回复 又令我迷惑不解:
   看来是JIT的Bug。我昨天 提交了这个Bug,今天已经得到了答复:
   This has been fixed in Whidbey RTM.
  既然不是Bug,怎么说“has been fixed”了呢?
  
在MSDN Product Feedback Center得到的答复也非常中肯,还给了很好的建议:
Actually the behaviour is correct and by design.

The mistake in you logic is that you assume that, because the expression is evaluated right-to-left for precedence, the variable locations are also taken from right to left at runtime.

This only goes to show that you should parenthesize your code well, use well-named temporary variables abundantly and generally not write code that is so confusing that not even you yourself knows what it means :-)

Mads Torgersen

  正是因为我做了错误的假设C#中的行为应该跟C++中的行为一样,发现问题后又没有去查C# Language Specification,才闹了这么一幕笑话。一定吸取教训!

修改于2005年8月22日 23:56
修改于2005年8月29日 01:55

以下是一个基于C51和ADC0809的排线测试程序,可以检测排线的短路、断路和错连,并使用LED灯和蜂鸣器提示故障类型和位置: ```C #include <reg52.h> #define uchar unsigned char #define uint unsigned int sbit CLK = P3^4; sbit ST = P1^0; sbit OE = P1^1; sbit EOC = P1^2; sbit A = P1^3; sbit B = P1^4; sbit C = P1^5; sbit Buzz = P3^2; sbit LED0 = P2^0; sbit LED1 = P2^1; sbit LED2 = P3^2; sbit LED3 = P2^3; sbit LED4 = P2^4; sbit LED5 = P2^5; sbit LED6 = P2^6; sbit LED7 = P2^7; sbit LED8 = P3^7; sbit LED9 = P3^6; sbit LED10 = P3^5; uchar code LED_PIN[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x80, 0x40, 0x20}; // LED灯对应的引脚 void delay(uint ms) { uint i, j; for (i = 0; i < ms; i++) { for (j = 0; j < 125; j++); } } void writeLED(uchar index, uchar value) { if (index < 8) { P2 &= ~(1 << index); P2 |= (value << index); } else if (index < 11) { P3 &= ~(1 << (index - 8)); P3 |= (value << (index - 8)); } } void resetLED() { P2 = 0xFF; P3 &= 0x1F; } uchar readADC(uchar channel) { uchar value; A = channel & 0x01; B = channel & 0x02; C = channel & 0x04; OE = 0; ST = 1; ST = 0; OE = 1; while (!EOC); CLK = 1; value = P1; CLK = 0; return value; } void testWire() { uchar i, j, k; for (i = 0; i < 5; i++) { for (j = i + 1; j < 5; j++) { if (readADC(i) == readADC(j)) { // 发现短路故障 writeLED(i, 1); writeLED(j, 1); LED0 = 1; Buzz = 1; delay(500); LED0 = 0; Buzz = 0; } else { writeLED(i, 0); writeLED(j, 0); } } if (readADC(i) > 200) { // 排线导通 writeLED(i, 1); } else { // 排线断开 writeLED(i, 0); LED1 = 1; Buzz = 1; delay(500); LED1 = 0; Buzz = 0; } } resetLED(); } void testConnection() { uchar i, j, k; for (i = 0; i < 5; i++) { for (j = i + 1; j < 5; j++) { if (readADC(i) == readADC(j)) { // 发现短路故障 writeLED(i, 1); writeLED(j, 1); LED0 = 1; Buzz = 1; delay(500); LED0 = 0; Buzz = 0; } else { writeLED(i, 0); writeLED(j, 0); } } if (readADC(i) > 200) { // 排线导通 writeLED(i, 1); } else { // 排线断开 writeLED(i, 0); LED1 = 1; Buzz = 1; delay(500); LED1 = 0; Buzz = 0; } } resetLED(); } void testReverse() { uchar i, j, k; for (i = 0; i < 5; i++) { for (j = i + 1; j < 5; j++) { if (readADC(i) == readADC(j)) { // 发现短路故障 writeLED(i, 1); writeLED(j, 1); LED0 = 1; Buzz = 1; delay(500); LED0 = 0; Buzz = 0; } else if ((i == 0 && j == 1) || (i == 2 && j == 3) || (i == 1 && j == 2) || (i == 3 && j == 4)) { if (readADC(i) > 200 && readADC(j) < 50) { // 发现错连故障 writeLED(i, 1); writeLED(j, 0); LED0 = 1; LED1 = 1; Buzz = 1; delay(500); LED0 = 0; LED1 = 0; Buzz = 0; delay(500); LED0 = 1; LED1 = 0; delay(1000); LED0 = 0; LED1 = 1; delay(1000); writeLED(i, 0); writeLED(j, 1); LED1 = 0; } else { writeLED(i, 0); writeLED(j, 0); } } } if (readADC(i) > 200) { // 排线导通 writeLED(i, 1); } else { // 排线断开 writeLED(i, 0); LED1 = 1; Buzz = 1; delay(500); LED1 = 0; Buzz = 0; } } resetLED(); } void main() { while (1) { testWire(); testConnection(); testReverse(); } } ``` 这个程序使用了C51单片机和ADC0809芯片来读取排线上每个导线的电压值,并根据电压值来判断故障类型和位置。需要注意的是,ADC0809芯片的输入电压范围是0-5V,需要根据实际情况设置参考电压和电阻分压比,以保证测量精度和稳定性。另外,程序中使用了简单的延时函数和LED输出函数,实际应用中可能需要进行一些优化和改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值