搜索
bottom↓
回复: 94

能不能把高八位和低八位合起来,成为一个16位数

[复制链接]

出0入0汤圆

发表于 2010-6-6 09:48:49 | 显示全部楼层 |阅读模式
例如TH1=0DH,TL1=EFH,把他们合起来成为0DEFH放在寄存器里

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

发表于 2010-6-6 09:52:51 | 显示全部楼层
可以啊。
unsigned int temp;
temp=TH1;
temp<<=8;
temp+=TL1

出0入0汤圆

发表于 2010-6-6 10:08:54 | 显示全部楼层
unsigned int temp;

temp=(TH1<<8)|TL1;

出0入0汤圆

发表于 2010-6-6 12:22:40 | 显示全部楼层
2楼的不行的

TH1左移8位后是0

出0入0汤圆

发表于 2010-6-6 12:50:50 | 显示全部楼层
楼上有试过吗?

出0入0汤圆

发表于 2010-6-6 12:56:41 | 显示全部楼层
【3楼】 chess01 =CHESS

是吗?

你为什么不去写一下再说呢?

我并没有改变TH1和TL1的值,我只读取它们的值。

出0入0汤圆

发表于 2010-6-6 13:05:19 | 显示全部楼层
2楼的写法的确在不同的编译器或不同的优化下,会有不同的结果

1楼的写法比较可靠

出0入0汤圆

发表于 2010-6-6 13:14:56 | 显示全部楼层
【6楼】 avr741

你可以举个例子说明下在哪种编译器的编译结果会不正确。


如果你想要多打几个字或要标准的话,那你可以这么用,不过我觉得有点多余。

unsigned int temp;

temp=((unsigned int)(TH1<<8))|TL1;

出0入0汤圆

发表于 2010-6-6 14:04:36 | 显示全部楼层
>>unsigned int temp;  

>>temp=((unsigned int)(TH1<<8))|TL1;

这样的结果还是和2楼的差不多,有两个可能的转换点会出错

第一  TH1是8位的 (TH1<<8) 就有可能是用8位的移位 , 移完的结果 = 0

第二  TL1也是8位的, 16位和8位的作逻辑操作, 也有可能只用8位的运算,结果也是8位的,再赋值给16位的temp,也只是高8位補0而已

出0入0汤圆

发表于 2010-6-6 14:26:39 | 显示全部楼层
【8楼】 avr741

请用你说的这种编译器切图出来说明你说的是对的。


我在5楼说过了,我只是读取TH1和TL1,并没有对TH1和TL1进行移位等操作。

而且一般的编译器对这种移位8次不是实际的移位,而是真接赋值,将低位的值直接赋值给高位。

而且对TL1的或运算也是直接赋值的,而不会进行或运算。(这样效率相当高)

出0入0汤圆

发表于 2010-6-6 14:45:03 | 显示全部楼层
我用联合体的。。-。-!

出0入0汤圆

发表于 2010-6-6 15:07:35 | 显示全部楼层
我也觉得联合体比较方便,既方便拆分,又方便合起来,而且没有计算过程,
可以看下这个帖子http://www.wang1jin.com/bbs/viewthread.php?tid=464&highlight=%C1%AA%BA%CF%CC%E5

出0入0汤圆

发表于 2010-6-6 15:23:41 | 显示全部楼层
联合体也是一种高效的方法,但是需要定义,写的麻烦。

我的方法实际上的操作跟联合体是一样的操作(没有计算过程),但不需要定义。


逆过程用:

unsigned char x,y;

x=temp>>8;  //取高位
y=temp;     //取低位

出0入0汤圆

发表于 2010-6-6 15:58:21 | 显示全部楼层
我一时没法找到之前会出问题的旧编译器

但我贴上另一种写法16+16=32,就是用IAR AVR 4.30A


(原文件名:test.JPG)

1楼的写法结果完全正确

而2楼写法会报错,编出来的代码也不对

出0入0汤圆

发表于 2010-6-6 16:46:39 | 显示全部楼层
1楼

出0入0汤圆

发表于 2010-6-6 18:02:53 | 显示全部楼层
【13楼】 avr741

我觉得不是编译器的问题,是你的问题,你有没想过1楼的为什么能通过,而我的通不过?

我想编译器默认的类型为16的整型,

我取一个8位数移动8位,它还在16位的范围内,

而你将一个16位数移16位,已经超出了16位的范围,所以你是错的,正确的写法是这样,你可以试试:

temp=(((unsigned long)OCR1B)<<16)|OCR1A;

出0入0汤圆

发表于 2010-6-6 18:42:23 | 显示全部楼层
改了一下


(原文件名:test2.JPG)

结果是正确的,也就是5楼的会比2楼的好

5L:"如果你想要多打几个字或要标准的话,那你可以这么用,不过我觉得有点多余。 "

结论,不是多余的!



注意我红线标出来的警告,那又是另一个问题


还有,用联合体要注意,不是每个编译器都高8位和低8位在内存的摆放顺序都是一样的,就是大端和小端的差别

出0入0汤圆

发表于 2010-6-6 18:51:44 | 显示全部楼层
真是不嫌麻烦,我都用 (TH1*256+TL1) ,还没遇到哪个编译器能傻到连乘2^N都真的产生乘法指令.

出0入0汤圆

发表于 2010-6-6 18:58:07 | 显示全部楼层
【16楼】 avr741

。。。我很无语,7楼是对之前所说的(temp=((unsigned int)(TH1<<8))|TL1;)情况。

你把它放到了16+16上能怪谁呢? 能有简单的写法,或默认值,你何必要去写复杂的呢?


你指的红线的问题可以不用管,如果你一定要去掉这个警告,请这么写代码:

unsigned long temp;
unsigned int h,l;

h=OCR1B;
l=OCR1A;

temp=(((unsigned long)h)<<16)|l;

出0入0汤圆

发表于 2010-6-6 19:05:26 | 显示全部楼层
回复【17楼】shark
真是不嫌麻烦,我都用 (th1*256+tl1) ,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------

我也一直这么干的

出0入0汤圆

发表于 2010-6-6 19:25:00 | 显示全部楼层
其实方法是很多了

(th1*256+tl1)也是一个不错的方法, 因为数据量很小,但是这个应该是不够高效的

th1*256没问题,问题在后面+tl1,是一个16位的加法。

出0入0汤圆

发表于 2010-6-6 19:59:59 | 显示全部楼层
"。。。我很无语,7楼是对之前所说的(temp=((unsigned int)(TH1<<8))|TL1;)情况。 "

"你把它放到了16+16上能怪谁呢? 能有简单的写法,或默认值,你何必要去写复杂的呢? "

"我想编译器默认的类型为16的整型, "

既然你的前提是默认值是16位,如果碰到默认值不是16位整型的C编译器呢? 也许是8位的,也许是32位的

1楼的方法不但8+8可以用,16+16也没问题

我之所以故意要用16+16来让IAR出错,只是要点出,你2楼的方法不能算是通用的,就算在现今大多主流的编译器都没问题

但是这样的写法当要移植到别的编译器或芯片,可能会出错,编译器会报错那还算是好事

如果编译器不会报错,编出来的代码,你就慢慢DEBUG吧!

出0入0汤圆

发表于 2010-6-6 20:29:29 | 显示全部楼层
【21楼】 avr741

引用"我之所以故意要用16+16来让IAR出错"

你牛,原来是你故意出错的啊?(我希望真的是这样的)


unsigned int temp;

temp=(TH1<<8)|TL1;

还是那句话,你给我找个会编译得不到正确结果的编译器。

出0入0汤圆

发表于 2010-6-6 20:43:06 | 显示全部楼层
我从来没说一楼的方法不好或不对,如果认为一楼好就用一楼了,就算我多嘴好了。

我只是想给大家一个更好的方法而以,没办法,再多嘴一句,如果用一楼的需要改改:

unsigned int temp;
temp=TH1;
temp<<=8;
temp+=TL1;   //原内容


unsigned int temp;
temp=TH1;
temp<<=8;
temp|=TL1;   //改动的地方

这样就是一个纯赋值语句了,代码量会少,执行时间也会变短。

出0入0汤圆

发表于 2010-6-6 21:02:35 | 显示全部楼层
回复【23楼】hsztc
我从来没说一楼的方法不好或不对,如果认为一楼好就用一楼了,就算我多嘴好了。
我只是想给大家一个更好的方法而以,没办法,再多嘴一句,如果用一楼的需要改改:
unsigned int temp;  
temp=th1;  
temp&lt;&lt;=8;  
temp+=tl1;   //原内容



unsigned int temp;  
temp=th1;  
temp&lt;&lt;=8;  
temp|=tl1;   //改动的地方
这样就是一个纯赋值语句了,代码量会少,执行时间也会变短。

-----------------------------------------------------------------------

同意【23楼】 hsztc ,效率高而且可靠不容易出错~

出0入0汤圆

发表于 2010-6-6 23:24:27 | 显示全部楼层
这个 就用1楼的就可以了
就这么一两行程序没必要那么较真  影响不到哪儿去

出0入0汤圆

发表于 2010-6-7 00:37:13 | 显示全部楼层
看来TFT的16位数据可以这样写了

出0入0汤圆

发表于 2010-6-7 08:49:36 | 显示全部楼层
赞同hsztc 的方法,我也认为hsztc 的方法技高一筹。

出0入0汤圆

发表于 2010-6-7 09:01:11 | 显示全部楼层
晕,没想到这么一个问题引发了这么大的讨论

出0入0汤圆

发表于 2010-6-7 09:31:30 | 显示全部楼层
回复【17楼】shark
真是不嫌麻烦,我都用 (th1*256+tl1) ,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------

我一般也是这么干的,有时候用指针+强制类型转换

u8 * t[2];
u16 x;
t[0]=th;
t[1]=tl;
x=*((u16 *)t);

x即为所求;注意不同的单片机下高低字节顺序不同,像avr和stm32就是相反的,用时需要注意th与tl的顺序。
建议直接使用数组里的元素替代tl与th,x可以是个u16的指针,初始化的时候直接指向t,这样转换起来几乎不花时间。

此法在读16位以上adc的spi时很方便,一个指针传过去,spi寄存器的值直接写到u8的数组里,读的时候强制类型转换成u16就行了。也可以把一个u16数的地址转换成u8的当函数变量,函数结束后u16数的值就是所需的了。用法多样,很灵活。

特别是有24位、或者多路数据的时候,特别节省运算时间。

出0入0汤圆

发表于 2010-6-7 17:22:14 | 显示全部楼层
【29楼】 ilawp

你的方法其实就是共用体(联合体)的变型了。

union uni2Byte
    {
        unsigned int all;
        unsigned char t[2];
    };
然后
union uni2Byte x;
x.t[0]=TH1;
x.t[1]=TL1;

x.all就是所求的16位数。(同样要注意大小端问题)

这种方法效率是最高的,数据量大时可以这么用,数据量不大感觉写的麻烦。

出0入0汤圆

发表于 2010-6-7 17:32:03 | 显示全部楼层
简单点,就是个联合体,如楼上所说,最简单

typedef union LONGDATA{                // Access LONGDATA as an
   unsigned long result;               // unsigned long variable or
   unsigned char Byte[4];              // 4 unsigned byte variables
}LONGDATA;

static LONGDATA rawValue;
rawValue.Byte[Byte3] = 0x00;
rawValue.Byte[Byte2] = (unsigned char)ADC0H;
rawValue.Byte[Byte1] = (unsigned char)ADC0M;
rawValue.Byte[Byte0] = (unsigned char)ADC0L;
mV = rawValue.result / 6710;        // Because of bounds issues, this

出0入8汤圆

发表于 2010-6-7 17:42:29 | 显示全部楼层
union        
{        /*定义占用一个字的共用体,可以实现字或两个字节的存取*/
        uint16_t d16;
        uint8_t  d8[2];        //d8[0]存放dat16低位,d8[1]存放dat16高位
}word;

出0入8汤圆

发表于 2010-6-7 17:43:44 | 显示全部楼层
回复【17楼】shark  
真是不嫌麻烦,我都用&#160;(th1*256+tl1)&#160;,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------

th1是8位的,不会溢出?

出0入0汤圆

发表于 2010-6-7 17:57:44 | 显示全部楼层
回复【33楼】rube 永丰庵
回复【17楼】shark   
真是不嫌麻烦,我都用 (th1*256+tl1) ,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------
th1是8位的,不会溢出?
-----------------------------------------------------------------------

又不把结果放入th1

出0入0汤圆

发表于 2010-6-7 18:44:17 | 显示全部楼层
我五楼就说了这么写只是读取TH1的值,并没有操作TH1,很多人都认为TH1是8位的,怎么移位都是8位的。

出0入0汤圆

发表于 2010-6-7 19:09:54 | 显示全部楼层

(原文件名:447.JPG)

出0入0汤圆

发表于 2010-6-7 19:13:50 | 显示全部楼层
注意这三行.尤其是第三行,就是 (TH1<<8) , 结果等于 0

000003: 0422  MOV   A, 0x22     [    34]
000004: 0050  MOV   0x10, A     [    16]
000005: 00D0  CLR   0x10        [    16]


但是1楼的写法编出来的代码没问题

出0入0汤圆

发表于 2010-6-7 19:31:31 | 显示全部楼层
7楼的写法

    temp=((unsigned short int)(TH1<<8))|TL1;

编出来的代码

000003: 0422  MOV   A, 0x22     [    34]   TH1
000004: 0052  MOV   0x12, A     [    18]

000005: 00D2  CLR   0x12        [    18]   <<8

000006: 0412  MOV   A, 0x12     [    18]   (unsigned short int)
000007: 0052  MOV   0x12, A     [    18]
000008: 00D3  CLR   0x13        [    19]

000009: 0423  MOV   A, 0x23     [    35]   TL1
00000A: 0050  MOV   0x10, A     [    16]
00000B: 00D1  CLR   0x11        [    17]

00000C: 0410  MOV   A, 0x10     [    16]   |
00000D: 0252  OR    0x12, A     [    18]
00000E: 0411  MOV   A, 0x11     [    17]
00000F: 0253  OR    0x13, A     [    19]

000010: 0412  MOV   A, 0x12     [    18]   temp=
000011: 0060  MOV   0x20, A     [    32]
000012: 0413  MOV   A, 0x13     [    19]
000013: 0061  MOV   0x21, A     [    33]

000014: 0012  RET                     


和2楼的结果一样,是错的


"我五楼就说了这么写只是读取TH1的值,并没有操作TH1,很多人都认为TH1是8位的,怎么移位都是8位的。 "

回家好好把C语言的型(type)及型转换(type casting)看一遍,就会知道为什么 "很多人" 都说 "TH1是8位的,怎么移位都是8位的"

出0入0汤圆

发表于 2010-6-7 19:39:18 | 显示全部楼层
学习!

出0入0汤圆

发表于 2010-6-7 22:53:56 | 显示全部楼层
【38楼】 avr741

7楼应该是个笔误,你试试这个(请参考15楼的写法)

temp=(((unsigned short int)TH1)<<8)|TL1;

如果这样还不行的话,说明你的译编器OUT了。


叫我回去看书的你是第二个,请推存本书能够说明我这句话是错的

"我五楼就说了这么写只是读取TH1的值,并没有操作TH1,很多人都认为TH1是8位的,怎么移位都是8位的。 "

出0入0汤圆

发表于 2010-6-7 23:37:47 | 显示全部楼层
to【40楼】 hsztc  
--------------------------------
印象中按C语言标准,移位操作前char应自动转换int然后再执行,所以
TH1<<8的值应该等价于 ((int)(TH1))<<8 ,但不排除某些8位机编译器不做这个转换(比如36楼的EMC的编译器),所以后者可以算作加了一个保险吧。

出0入0汤圆

发表于 2010-6-7 23:55:31 | 显示全部楼层
这个编译器我试过了, 15楼的 和 17楼的TH1*256+TL1 都是正确的, 这个编译器是这家公司的网站上目前最新的版本(2009年的)

不是这个编译器OUT, 也不是我牛,能让IAR出错(16+16时)

而是你在2楼和7楼的写法就是有潜在的问题!


我想任何一本C语言的书都会提到 型转换(type casting) 而且还有分 指示性(强制性的)和非指示性(自动的)型转换

你的问题就在于 "非指示性(自动的)型转换" 出了问题, 这个你自己回去去看书吧 网上也找得着这类的说明

以你上面的态度,我提醒你的已经够多了

出0入0汤圆

发表于 2010-6-8 01:20:06 | 显示全部楼层
【42楼】 avr741

我说的有错吗?请回答我40楼问题,如果temp=(((unsigned short int)TH1)<<8)|TL1;  

这样写还有问题的话,这编译器真OUT了,切出图来看看?

不过有一点我真得认错,temp=(TH1<<8)|TL1; 还真有编译"出错"的编译器,确实有不一样的情况,长见识了。


IAR并没有出错,出错的是你,IAR只是对你写的内容进行编译,只能说编译的结果和你想要的不一样而以。

如果你表达清楚了你的意思,IAR就能编译出你所要的结果。

每个方法都有特定的局限性,如果不知道怎么灵活应用,只会照搬的话难免出错。

出错了又知道怎么去改,就出来大叫,这样会让我很郁闷,还得花大把时间跟你解释,

如果你知道哪里有问题你直接说出来就行了,把你可行的方法说出来,而不是举反面例子。


至于你为什么叫我看型类转换我真搞不明白。


关于态度问题,你应该得反省下,随便叫人回家看书是不尊重人的,你去坛里转转有几个敢这么说别人的。

出0入0汤圆

发表于 2010-6-8 09:50:53 | 显示全部楼层
"请回答我40楼问题,如果temp=(((unsigned short int)TH1)<<8)|TL1;  "

我都说了,15楼(也就是40楼)的算法没错,你看仔细点


"不过有一点我真得认错,temp=(TH1<<8)|TL1; 还真有编译"出错"的编译器,确实有不一样的情况,长见识了。 "

现在肯认错了就好 如果还不认错,我就学习1楼的不解释 3楼的不回应以保持论坛的和谐

等那天你设计生产出来的产品出了这个问题,你去跟老板认错吧!


"每个方法都有特定的局限性,如果不知道怎么灵活应用,只会照搬的话难免出错。 "

1楼的方法没有一个编译器会出问题,包括16+16=32也不会

17楼的 TH1*256+TL1 也不会出问题

为什么你2楼的算法就有局限性? 自己出了问题还怪别人"不知道怎么灵活应用,只会照搬"?


"出错了又知道怎么去改,就出来大叫,"   应该是少了一个"不"  "出错了又不知道怎么去改"

看看我的原文 "注意我红线标出来的警告,那又是另一个问题" 这只是我提醒你还有别的问题

你当真以为我是天堂里的猪脑袋,不知道怎么改吗? 来求你告诉我怎么改吗?


"关于态度问题,你应该得反省下,随便叫人回家看书是不尊重人的,你去坛里转转有几个敢这么说别人的。 "

因为这是很基本的问题,书上都有,叫你回家看书的我也不是第一个(这是你说的,我也不知道还有谁也叫你回家看书)

我只是提醒你的写法可能会有问题,那你动不动叫我截图出来给你看,动不动叫我花时间去找编译器,就不会不尊重人吗?

出0入0汤圆

发表于 2010-6-8 10:18:10 | 显示全部楼层
"如果你知道哪里有问题你直接说出来就行了,把你可行的方法说出来,而不是举反面例子。 "
"至于你为什么叫我看型类转换我真搞不明白。"

其实真正的问题,我在这个主题其中一个贴子已经解释过了

可能你看我积分很少,认为我所说的话都是没价值的,是不可信的,甚至是错的,所以你根本不用心看

才会叫你回家看书,因为书上说的,你总不能不信吧!

出0入0汤圆

发表于 2010-6-8 10:59:16 | 显示全部楼层
hsztc 并没有理解数据类型转换,而且太不谦虚。
avr741 很有耐心。


简单的说有些编译器能自动转换数据类型,但不是所有的编译器都会这么做,TH1<<8的结果是什么取决于TH1的数据类型!
之所以 TH1<<8 或 TH1*256 能得到正确的结果是因为编译器自动进行了转换。

出0入0汤圆

发表于 2010-6-8 11:04:14 | 显示全部楼层
1楼最好。
2楼的写法垃圾。
鉴定完毕。

出0入0汤圆

发表于 2010-6-8 12:10:01 | 显示全部楼层
回复【47楼】aviator
hsztc 并没有理解数据类型转换,而且太不谦虚。
avr741 很有耐心。
简单的说有些编译器能自动转换数据类型,但不是所有的编译器都会这么做,th1&lt;&lt;8的结果是什么取决于th1的数据类型!
之所以 th1&lt;&lt;8 或 th1*256 能得到正确的结果是因为编译器自动进行了转换。

-----------------------------------------------------------------------

*256应该比较安全,因为256已经超过u8的范围了,编译器只要不傻就会自动转换成int来算

出0入0汤圆

发表于 2010-6-8 13:12:06 | 显示全部楼层
【44楼】 avr741
"请回答我40楼问题,如果temp=(((unsigned short int)TH1)<<8)|TL1;  "

我都说了,15楼(也就是40楼)的算法没错,你看仔细点
------------------------------------------------------------------------------

这个很说明问题了,你就是来显的,既然你看出了问题,你在8楼就应该指出
“temp=((unsigned int)(TH1<<8))|TL1;”
这么写是错的,应该这么写
“temp=(((unsigned int)TH1)<<8)|TL1;”

下面就少浪费多少时间在这上面。而7楼的写法确实是有问题的,后来才发现的

(unsigned int)放错了位置,在40楼已经指出了。之所以要省掉这句(unsigned int)就是为了写法上的简化

真没想到会有编译器不能正确编译,所以在7楼把(unsigned int)加了上去,但没注意看加错了位置。

而且我真没遇到过不能编译的正确编译器,所以基本省略掉了这句,你不切个图我无法相信。


-----------------------------------------------------------------------------------------
"每个方法都有特定的局限性,如果不知道怎么灵活应用,只会照搬的话难免出错。 "

1楼的方法叫通用性强,我指的是我的方法存在的优化有局限性,我的方法在写法上和算法上存在优化,

而优化不是随随便便都行的,需要跟踞不同的编译器和不同类型的单片机而有所不同。

而我7楼给出的是在写法上没有省略的写法,所以可以和一楼一样通用,不存在局限性。
(别在这挑骨头,指的是7楼修正后的“temp=(((unsigned int)TH1)<<8)|TL1;”)



"出错了又知道怎么去改,就出来大叫,"   应该是少了一个"不"  "出错了又不知道怎么去改"

看看我的原文 "注意我红线标出来的警告,那又是另一个问题" 这只是我提醒你还有别的问题

你当真以为我是天堂里的猪脑袋,不知道怎么改吗? 来求你告诉我怎么改吗?

-------------------------------------------------------------------------
我知道你知道怎么改,但你就是不改,你得说我的不行啊,改了怎么显的你是对的呢?


叫你截图我觉得不存在问题,我确实没见过会出错的编译器,所以想看看。

不过看了你编译器出的代码,感觉这个编译器效率很低,简单的算法生成一堆代码。

至于叫我回家看书的确实你不是第一个,还有个我们坛的年过60的老前辈,刚搜了下地址,见22楼

http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=3357325&bbs_page_no=1&search_mode=1&search_text=usb&bbs_id=3049

学学人家是怎么说的。积分不是问题,你看看这个前辈积分多少,不过积分少的来找事的确实会多点。

出0入0汤圆

发表于 2010-6-8 14:04:39 | 显示全部楼层
先上一张截图,是别的网站的,部分ID已隐去


(原文件名:60elder.JPG)

先看看别人是如何立马认错的,再看看你自己的态度又是如何



看来你还是没有找到问题的关键,只会在什么7楼,15楼,40楼,编译器的效率很低上面作文章

出0入0汤圆

发表于 2010-6-8 15:20:31 | 显示全部楼层
【5楼】 hsztc

积分:1112
派别:
等级:------
来自:福建省
【3楼】 chess01 =CHESS

是吗?

你为什么不去写一下再说呢?

我并没有改变TH1和TL1的值,我只读取它们的值。  

==========================================
不是搞人身攻攻击哈,你在2楼的写法想都不用想,它就是错的。
TH1与TL1是没变,但var=(TH1<<8)这个var始终是0

出0入0汤圆

发表于 2010-6-8 17:53:50 | 显示全部楼层
回复【52楼】MZ_Guo
不是搞人身攻攻击哈,你在2楼的写法想都不用想,它就是错的。
th1与tl1是没变,但var=(th1&lt;&lt;8)这个var始终是0
-----------------------------------------------------------------------
看看C99的标准是怎么说的:

(原文件名:shift.JPG)

<< 操作符要求两个操作数都是integer类型的,如果不是则自动提升为integer类型。
所以TH<<8和((int)(TH))<<8 是等价的,不过某些编译器没有遵循标准。

出0入0汤圆

发表于 2010-6-8 18:09:51 | 显示全部楼层
"<< 操作符要求两个操作数都是integer类型的,如果不是则自动提升为integer类型"
"所以TH<<8和((int)(TH))<<8 是等价的,"

这个是对的!

"不过某些编译器没有遵循标准。 "

如过你是说EMC的话, 这个不是事实


既然你遇到问题已经有去查书了,比起 hsztc 好太多,我就提醒你看一下我在21楼的

"既然你的前提是默认值是16位,如果碰到默认值不是16位整型的C编译器呢? 也许是8位的,也许是32位的 "

应该可以解释你在41楼的疑惑

出0入0汤圆

发表于 2010-6-8 18:32:12 | 显示全部楼层
【51楼】 avr741

你扯远了,我不想在这问题上再和你浪费时间。

不过得说在2楼和7楼上确实犯了错。

2楼没有考虑到某些编译器的问题。

7楼存在笔误,正确写法在15楼和40楼。




【52楼】 MZ_Guo

不是搞人身攻攻击哈,你在2楼的写法想都不用想,它就是错的。
-----------------------------------------------------------

想都不用想?今天让你开开眼界。


“TH1与TL1是没变,但var=(TH1<<8)这个var始终是0 ”

如果var为int呢?

如:
unsigned int var;

var=TH1<<8;  这还是始终是0吗?

希望大家看了以上两行能明白我说的。

我也切些图给你看看。



最后回复一次,是非由大家自己分辩。

我说话是很直,但很真,从不拐弯抹角,没办法天生就这样,得罪人的请多包含。

51的KEIL够专业吧,难道它也会错,IAR呢? ICCAVR呢?我电脑上就这几个C编译器,很负责的告诉你

这几个软件编译2楼temp=(TH1<<8)|TL1; 都是又简捷又准确。

KEIL,IAR FOR 51 ,ICCAVR,IAR FOR AVR 没有一个编译(temp=(TH1<<8)|TL1; )这段代码结果超过5条汇编指令的。

对比【36楼】 avr741 到 【38楼】 avr741  的这个软件,生成一堆堆的汇编又是错的。

所以遇到偏冷的编译器的时候还是老老实实的写全代码。



(原文件名:iarfor511.PNG)


(原文件名:iarfor512.PNG)

这是IAR FOR 51的结果,红色框内为生成的(temp=(TH1<<8)|TL1;)


(原文件名:keil1.PNG)


(原文件名:keil2.PNG)

这是KEIL C51的结果,红色框内为生成的(temp=(TH1<<8)|TL1;)


(原文件名:icc1.PNG)


(原文件名:icc2.PNG)

这是ICCAVR的结果,红色框内为生成的(temp=(TH1<<8)|TL1;)


(原文件名:iarforavr1.PNG)


(原文件名:iarforavr2.PNG)

这是IAR FOR AVR的结果,红色框内为生成的(temp=(TH1<<8)|TL1;)

出0入0汤圆

发表于 2010-6-8 18:38:50 | 显示全部楼层
打个注解:刚回来看到有回复了,所以在这边写回复,没想到写的时间长了点,当时并没有看到53楼和54楼,提交后才看到的。

出0入0汤圆

发表于 2010-6-8 18:50:37 | 显示全部楼层
回复【54楼】avr741
如过你是说emc的话, 这个不是事实
-----------------------
我只用过GCCAVR,IAR,KEILC,PC上用过VC,BC,GCC ,没用过EMC编译器,如果EMC的int是16位的话,你的截图看来,EMC并没有遵循标准,当然如果它的int是8位的另当别论,但它实际上并不是8位的int。


"既然你的前提是默认值是16位,如果碰到默认值不是16位整型的c编译器呢? 也许是8位的,也许是32位的 "
-----------------------------------------------------------------------
或许4位机的int是8位的,不过我没接触过。
32位的毫无问题,32位编译器的int就是32位的,标准只要求<<的操作数是int类型,其它的是程序员的责任。

出0入0汤圆

发表于 2010-6-8 19:15:19 | 显示全部楼层
回复【57楼】shark
-----------------------------------------------------------------------

"当然如果它的int是8位的另当别论,但它实际上并不是8位的int。 "  错!它就是8位的

你可能还是没有注意到,EMC的 int 就是8位的,我程序里的 temp 是 unsigned short int 是16位的, long int 是32位

正如你53楼截图,C语言书里面没有一句话提到8位或16位 只说是integer type

还有,int是8/16/32没有一定,要看编译器和CPU的定位以及容量,EMC是8位MCU,int是8位,8051也是8位MCU,但IAR51,KEIL51的int都是16位

很多人都有这样的刻板印象,char == 8, int == 16, long == 32 这个不是完全对的

出0入0汤圆

发表于 2010-6-8 20:46:50 | 显示全部楼层
粗略的看了下楼上各位的说法:

我也乱说几句。

(1)首先 很重要一点就是avr741 说的, 就是byte是8位的。但是其余的像int、long int 这些玩意到底是几位的 不同编译器可能就会不一样   所以 如果哪位的解释没有主意到这点  那么你的解释就可能让别人误解

(2)有人提到 C99标准。还引用了原文。 这个没有必要研究。编译器也没有必要完全遵守C标准。要清楚,我们搞的是嵌入式的编译器 ,我们的C语言和C发明者发明的C语言的是有区别的。
比如说 一般c语言说讲 指针运行会比数组快。但是,比如KEIL C51编译器中,数组要比指针快!

(3)有人提出要用联合体。我个人非常不喜欢用联合体,因为可能会带来大小端问题  移植差

(4)可以考虑用 那个  H1 * 256 + L1
(5)一般来讲  移位 和 “|” 一起用 不会出现什么问题
    但要特别注意: 移位 和 “取反~”一起用 在“不用的位数”的片子下 特别容易出问题

(6)依靠编译器进行自动转换 这种做法个人感觉比较不放心  还是强制转转 比较安心

出0入0汤圆

发表于 2010-6-8 20:56:16 | 显示全部楼层
EMC的单片机因为内存很少,而且大多是很小很简单的程序,所以这个编译器把 int 定成8位,以节省 int 变量占内存的容量

不排除也可以找到类似容量小的8051或PIC的编译器, int 也是8位的,并不是51的 int 就一定是16位的


"TH1<<8的值应该等价于 ((int)(TH1))<<8 ,但不排除某些8位机编译器不做这个转换(比如36楼的EMC的编译器),"

"不过某些编译器没有遵循标准。 "

因为2楼的(TH1 << 8),在EMC的编译器里它还是有把 TH1 从 char 提升到 int 再作移位

但因为 int 还是8位而造成溢出,就不能说是EMC编译器没有遵循C99的标准了


1楼和15楼的方法因为有强制提升到16位再作移位,自然就没问题

2楼就认为TH1一定会有强制提升到16位再作移位,事实上是强制提升到 integer 再作移位, 当integer小于16位(8位)时,就错了


最后我还发现一个最大的问题,楼主只学了51汇编,根本没学C语言,我们吵了几天,完全不对题

出0入0汤圆

发表于 2010-6-8 21:53:40 | 显示全部楼层
to【59楼】 xlsbz
(2)有人提到 C99标准。还引用了原文。 这个没有必要研究。编译器也没有必要完全遵守C标准。要清楚,我们搞的是嵌入式的编译器 ,我们的C语言和C发明者发明的C语言的是有区别的。
-----------------------------------------------------------
除了扩展语法,基本语法上嵌入式编译器还是要遵循C标准的,否则还定什么标准。
我知道没有什么编译器是100%符合C标准的,但基本语法和原则是没有异议的。



比如说 一般c语言说讲 指针运行会比数组快。但是,比如KEIL C51编译器中,数组要比指针快!
------------------------------
这个和标准无关,标准没有规定哪个快,实际上我实验的结果正好相反,指针要快一点。


【60楼】 avr741

如果EMC的int是8位的,那我同意60楼观点,不过这个编译器真是奇怪,short int比 int 还 “long" ,呵呵。
那在EMC中,常量256是什么类型,short int还是int, 如果它是int,那TH1*256结果也会是int,也会溢出,变成零,如何解释,请指教。

出0入0汤圆

发表于 2010-6-8 21:57:47 | 显示全部楼层
恩,用指针拼合最快了,直接就编译成MOV指令了,4-6周期搞定。

出0入0汤圆

发表于 2010-6-8 21:59:57 | 显示全部楼层
恩,用指针拼合最快了,直接就编译成MOV指令了,4-6周期搞定。

出0入0汤圆

发表于 2010-6-8 22:31:33 | 显示全部楼层

(原文件名:type.JPG)


"常量256是什么类型,short int还是int"
"如果它是int,那TH1*256结果也会是int,也会溢出,变成零,如何解释,请指教。"

当然是16位的short int,见上图

8位*16位,自然会自动提升成16*16,就不会有溢出的问题


这也是UCOS等OS都是用 u8 u16 u32 等 data type 来替代 char int long 的原因,才不容易搞错

出0入0汤圆

发表于 2010-6-9 21:26:03 | 显示全部楼层
回复【61楼】shark
-----------------------------------------------------------------------

你说的对   不过C发明者说 C规则是给编写编译器的人看的  所以没有太多时间的话 还是不看为妙

多花点时间在别的方面 比如刚出的CM3内核上  
这个不会过时 有用

出0入0汤圆

发表于 2010-6-9 22:31:39 | 显示全部楼层
看看ucosii的源码是怎么写的

os_mutex.c中的一个函数:



OS_EVENT  *OSMutexCreate (INT8U prio, INT8U *perr)
{
    OS_EVENT  *pevent;
#if OS_CRITICAL_METHOD == 3                                /* Allocate storage for CPU status register */
    OS_CPU_SR  cpu_sr = 0;
#endif



#if OS_ARG_CHK_EN > 0
    if (perr == (INT8U *)0) {                              /* Validate 'perr'                          */
        return ((OS_EVENT *)0);
    }
    if (prio >= OS_LOWEST_PRIO) {                          /* Validate PIP                             */
        *perr = OS_ERR_PRIO_INVALID;
        return ((OS_EVENT *)0);
    }
#endif
    if (OSIntNesting > 0) {                                /* See if called from ISR ...               */
        *perr = OS_ERR_CREATE_ISR;                         /* ... can't CREATE mutex from an ISR       */
        return ((OS_EVENT *)0);
    }
    OS_ENTER_CRITICAL();
    if (OSTCBPrioTbl[prio] != (OS_TCB *)0) {               /* Mutex priority must not already exist    */
        OS_EXIT_CRITICAL();                                /* Task already exist at priority ...       */
        *perr = OS_ERR_PRIO_EXIST;                         /* ... inheritance priority                 */
        return ((OS_EVENT *)0);
    }
    OSTCBPrioTbl[prio] = OS_TCB_RESERVED;                  /* Reserve the table entry                  */
    pevent             = OSEventFreeList;                  /* Get next free event control block        */
    if (pevent == (OS_EVENT *)0) {                         /* See if an ECB was available              */
        OSTCBPrioTbl[prio] = (OS_TCB *)0;                  /* No, Release the table entry              */
        OS_EXIT_CRITICAL();
        *perr              = OS_ERR_PEVENT_NULL;           /* No more event control blocks             */
        return (pevent);
    }
    OSEventFreeList        = (OS_EVENT *)OSEventFreeList->OSEventPtr;   /* Adjust the free list        */
    OS_EXIT_CRITICAL();
    pevent->OSEventType    = OS_EVENT_TYPE_MUTEX;
    pevent->OSEventCnt     = (INT16U)((INT16U)prio << 8) | OS_MUTEX_AVAILABLE; /* Resource is avail.   */
    pevent->OSEventPtr     = (void *)0;                                 /* No task owning the mutex    */
#if OS_EVENT_NAME_SIZE > 1
    pevent->OSEventName[0] = '?';
    pevent->OSEventName[1] = OS_ASCII_NUL;
#endif
    OS_EventWaitListInit(pevent);
    *perr                  = OS_ERR_NONE;
    return (pevent);
}

出0入0汤圆

发表于 2010-9-30 08:35:38 | 显示全部楼层
将高八位数据按照无符号数乘以8后与低八位数据相加。

出0入0汤圆

发表于 2010-9-30 14:27:44 | 显示全部楼层
一段程序引发的血案。。~~其实楼主的问题早解决了,~~

出0入0汤圆

发表于 2010-10-1 06:23:55 | 显示全部楼层
both are wrong, strictly speaking, and right, loosely speaking.

the issue here is type promotion in C. data types are promoted to "integer" before they are procssed. on a platform where int is of 8-bit, both approaches will result in TH<<8 to be 0.

the right approach is to explicitly force a promotion before shifting:

(((unsigned long/short) (TH)) << 8) | TL.

note that 1) I used "long"/"short" not "int" as long is always defined as 32-bit and short 16-bit but int can be anything. and 2) I forced a type promotion before shifting TH.

hope it helps.

出0入0汤圆

发表于 2010-10-1 08:38:38 | 显示全部楼层
靠,都在这里打口水仗,自己直接上计算机编程序模拟一下就知道了啊,在这里问还浪费不少时间。

出0入0汤圆

发表于 2010-10-1 08:49:49 | 显示全部楼层
这个我都是用指针操作!也很方便!

出0入0汤圆

发表于 2010-10-1 18:33:17 | 显示全部楼层
收益匪牵。

出0入0汤圆

发表于 2010-10-1 21:10:22 | 显示全部楼层
联合体与结构体共用。。。即可以整体操作,也可以单独操作!

出0入0汤圆

发表于 2010-10-1 22:59:03 | 显示全部楼层


unsigned int timer1;

EA=0;

do{
    timer1 = (unsigned int)(TH1 << 8) | TL1;
}while ( (timer1 >> 8 ) != TH1 );

EA=1;

出0入0汤圆

发表于 2010-10-2 10:08:29 | 显示全部楼层
LZ要知道一个问题,你用的是51单片机吧?8位的,得到16位的数字还不是用两个8位的字节来保存的?无论你怎么操作,最终还是以字节方式保存,所以别想的那么复杂了。比如这个程序编译的结果,Keil:

     5:                 unsigned int A;
     6:                 unsigned char B,C;
     7:                 A=0x55AA;
     8:                 B=0x11;
     9:                 C=0x19;
    10:                 A=B*256+C;
C:0x0003    7C00     MOV      R4,#0x00
C:0x0005    E4       CLR      A
C:0x0006    2419     ADD      A,#0x19
C:0x0008    FF       MOV      R7,A
C:0x0009    EC       MOV      A,R4
C:0x000A    3411     ADDC     A,#0x11
C:0x000C    FE       MOV      R6,A

可以判断出无符号整形变量A占用的地址是R6:R7,变量C根本没出现,就直接被复制到R7(低字节)了,变量B复制到A后,加上可能的进位就复制到R6,乘法没出现,更没有移位,只是简单的数据移动。

出0入0汤圆

发表于 2010-10-2 19:16:18 | 显示全部楼层
最简单的方法 C语言中 一个UNION 就 搞定!

出0入0汤圆

发表于 2010-10-2 22:08:21 | 显示全部楼层
学习了,呵呵!

出0入0汤圆

发表于 2010-10-3 00:37:27 | 显示全部楼层
我终于相信了金庸小说中的华山论剑舞林大会,高手对决就是不一样,收益匪浅啊。其实这样的讨论多一些还是好的。

出0入0汤圆

发表于 2010-10-7 17:13:20 | 显示全部楼层
......

這裡的人很強大...

出0入0汤圆

发表于 2010-10-7 20:30:16 | 显示全部楼层
16: unsigned int temp;   
    17:  
    18: ((unsigned char*) (&temp))[0] = TH1;
C:0x0B60    858D30   MOV      0x30,TH1(0x8D)
    19: ((unsigned char*) (&temp))[1] = TL1;
C:0x0B63    858B31   MOV      0x31,TL1(0x8B)

KEIL 51里这样用最简最优.注意移植性不好,要考虑大小端.


用移位法移植性好,但KIEL C做了很多无用功,目标代码长很多.

unsigned int temp;  

temp = ( (TH1<<8) | TL1);
C:0x0B60    AF8D     MOV      R7,TH1(0x8D)
C:0x0B62    EF       MOV      A,R7                 ---它到底想干啥?
C:0x0B63    AD8B     MOV      R5,TL1(0x8B)
C:0x0B65    F530     MOV      0x30,A
C:0x0B67    ED       MOV      A,R5                 ---它到底想干啥?
C:0x0B68    F531     MOV      0x31,A

出0入0汤圆

发表于 2010-10-7 22:24:32 | 显示全部楼层
高手有时候也会遇到更高的高手,呵呵。都消消火,心平气和说清楚不就结了,花这么多口水盖这么高的楼。。。

出0入0汤圆

发表于 2010-10-7 23:13:33 | 显示全部楼层
联合不可靠,不同的编译器int高低字节顺序是不同的,这样代码移植时会有麻烦。int = (((int)char_H)<<8)|chat_L 应该可靠的。

出0入0汤圆

发表于 2010-10-7 23:56:56 | 显示全部楼层
不记得在哪里看到的如下的声明了,个人觉得还是比较好用的
#define MakeWord(a, b)        ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
#define MakeDWord(a, b)        ((DWORD)(((WORD)(a)) | ((DWORD)((WORD)(b))) << 16))
另外关于数据类型转换还是自己做的比较好,以后再阅读代码也比较省心。即使更新了单片机,程序还可以跑起来。

出0入0汤圆

发表于 2010-10-8 01:54:43 | 显示全部楼层
很多人吃过亏回复【81楼】zhiwei
高手有时候也会遇到更高的高手,呵呵。都消消火,心平气和说清楚不就结了,花这么多口水盖这么高的楼。。。
-----------------------------------------------------------------------

人之常情.站在越高的楼上越容易往楼下看风景,因为更高的楼已经很少了,所以看到更高的楼时,第一反应会认为那是幻影.

出0入0汤圆

发表于 2010-10-9 20:19:04 | 显示全部楼层
更认同 avr741 的观点。他的思路更多地考虑了程序的可靠性。也许这样写出来的程序会稍显冗长,多花一些时间输入,但是在调试的时候,就会体会到这样的时间花的值得。这更多地体现的是一种编程风格。

感觉 hsztc 更倾向于代码的简练和效率,个人觉得这种风格在一些资源及其有限的项目中会有价值。但是从日常的使用来说,不建议采用这种编程风格。尤其在一个产品生命和维护周期很长,会由不同的人来负责这些代码的情况下,这种风格的程序可能就会是一个 bug 的来源了。

出0入0汤圆

发表于 2011-12-1 11:15:49 | 显示全部楼层
回复【80楼】rainyss
-----------------------------------------------------------------------

你的最好

出0入0汤圆

发表于 2011-12-1 11:16:03 | 显示全部楼层
回复【80楼】rainyss
-----------------------------------------------------------------------

你的最好

出0入0汤圆

发表于 2011-12-3 09:46:35 | 显示全部楼层
a=ds1820rd();//取温度低8位
  b=ds1820rd();//取温度高八位
  tvalue=b;
  tvalue<<=8;
  tvalue=tvalue|a;//第八位和高八位合在一起

出0入0汤圆

发表于 2012-2-23 17:32:31 | 显示全部楼层
13楼正解!

出0入0汤圆

发表于 2020-7-3 15:01:21 | 显示全部楼层
"
unsigned int temp;

temp=(TH1<<8)|TL1;
" 这个好用

出0入0汤圆

发表于 2020-7-8 17:37:33 | 显示全部楼层
看大家的讨论,学习很多,谢谢各位

出145入215汤圆

发表于 2020-7-10 02:02:24 来自手机 | 显示全部楼层
51单片机只有pc与dptr寄存器才是16位的。你可以把高8位放dph然后地八位放dpl就构成16位dptr了。定时器16位能干啥?

出0入0汤圆

发表于 2020-7-17 16:59:57 来自手机 | 显示全部楼层
看大家的讨论,学习很多,谢谢各位

出0入0汤圆

发表于 2021-1-27 14:12:52 | 显示全部楼层
都是高人,看帖学习
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-26 14:15

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表