能不能把高八位和低八位合起来,成为一个16位数
例如TH1=0DH,TL1=EFH,把他们合起来成为0DEFH放在寄存器里 可以啊。unsigned int temp;
temp=TH1;
temp<<=8;
temp+=TL1 unsigned int temp;
temp=(TH1<<8)|TL1; 2楼的不行的
TH1左移8位后是0 楼上有试过吗? 【3楼】 chess01 =CHESS
是吗?
你为什么不去写一下再说呢?
我并没有改变TH1和TL1的值,我只读取它们的值。 2楼的写法的确在不同的编译器或不同的优化下,会有不同的结果
1楼的写法比较可靠 【6楼】 avr741
你可以举个例子说明下在哪种编译器的编译结果会不正确。
如果你想要多打几个字或要标准的话,那你可以这么用,不过我觉得有点多余。
unsigned int temp;
temp=((unsigned int)(TH1<<8))|TL1; >>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而已 【8楼】 avr741
请用你说的这种编译器切图出来说明你说的是对的。
我在5楼说过了,我只是读取TH1和TL1,并没有对TH1和TL1进行移位等操作。
而且一般的编译器对这种移位8次不是实际的移位,而是真接赋值,将低位的值直接赋值给高位。
而且对TL1的或运算也是直接赋值的,而不会进行或运算。(这样效率相当高) 我用联合体的。。-。-! 我也觉得联合体比较方便,既方便拆分,又方便合起来,而且没有计算过程,
可以看下这个帖子http://www.wang1jin.com/bbs/viewthread.php?tid=464&highlight=%C1%AA%BA%CF%CC%E5 联合体也是一种高效的方法,但是需要定义,写的麻烦。
我的方法实际上的操作跟联合体是一样的操作(没有计算过程),但不需要定义。
逆过程用:
unsigned char x,y;
x=temp>>8;//取高位
y=temp; //取低位 我一时没法找到之前会出问题的旧编译器
但我贴上另一种写法16+16=32,就是用IAR AVR 4.30A
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_559959LSV4.JPG
(原文件名:test.JPG)
1楼的写法结果完全正确
而2楼写法会报错,编出来的代码也不对 1楼 【13楼】 avr741
我觉得不是编译器的问题,是你的问题,你有没想过1楼的为什么能通过,而我的通不过?
我想编译器默认的类型为16的整型,
我取一个8位数移动8位,它还在16位的范围内,
而你将一个16位数移16位,已经超出了16位的范围,所以你是错的,正确的写法是这样,你可以试试:
temp=(((unsigned long)OCR1B)<<16)|OCR1A; 改了一下
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_559979WL46.JPG
(原文件名:test2.JPG)
结果是正确的,也就是5楼的会比2楼的好
5L:"如果你想要多打几个字或要标准的话,那你可以这么用,不过我觉得有点多余。 "
结论,不是多余的!
注意我红线标出来的警告,那又是另一个问题
还有,用联合体要注意,不是每个编译器都高8位和低8位在内存的摆放顺序都是一样的,就是大端和小端的差别 真是不嫌麻烦,我都用 (TH1*256+TL1) ,还没遇到哪个编译器能傻到连乘2^N都真的产生乘法指令. 【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; 回复【17楼】shark
真是不嫌麻烦,我都用 (th1*256+tl1) ,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------
我也一直这么干的 其实方法是很多了
(th1*256+tl1)也是一个不错的方法, 因为数据量很小,但是这个应该是不够高效的
th1*256没问题,问题在后面+tl1,是一个16位的加法。 "。。。我很无语,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吧! 【21楼】 avr741
引用"我之所以故意要用16+16来让IAR出错"
你牛,原来是你故意出错的啊?(我希望真的是这样的)
unsigned int temp;
temp=(TH1<<8)|TL1;
还是那句话,你给我找个会编译得不到正确结果的编译器。 我从来没说一楼的方法不好或不对,如果认为一楼好就用一楼了,就算我多嘴好了。
我只是想给大家一个更好的方法而以,没办法,再多嘴一句,如果用一楼的需要改改:
unsigned int temp;
temp=TH1;
temp<<=8;
temp+=TL1; //原内容
unsigned int temp;
temp=TH1;
temp<<=8;
temp|=TL1; //改动的地方
这样就是一个纯赋值语句了,代码量会少,执行时间也会变短。 回复【23楼】hsztc
我从来没说一楼的方法不好或不对,如果认为一楼好就用一楼了,就算我多嘴好了。
我只是想给大家一个更好的方法而以,没办法,再多嘴一句,如果用一楼的需要改改:
unsigned int temp;
temp=th1;
temp<<=8;
temp+=tl1; //原内容
unsigned int temp;
temp=th1;
temp<<=8;
temp|=tl1; //改动的地方
这样就是一个纯赋值语句了,代码量会少,执行时间也会变短。
-----------------------------------------------------------------------
同意【23楼】 hsztc ,效率高而且可靠不容易出错~ 这个 就用1楼的就可以了
就这么一两行程序没必要那么较真影响不到哪儿去 看来TFT的16位数据可以这样写了 赞同hsztc 的方法,我也认为hsztc 的方法技高一筹。 晕,没想到这么一个问题引发了这么大的讨论 回复【17楼】shark
真是不嫌麻烦,我都用 (th1*256+tl1) ,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------
我一般也是这么干的,有时候用指针+强制类型转换
u8 * t;
u16 x;
t=th;
t=tl;
x=*((u16 *)t);
x即为所求;注意不同的单片机下高低字节顺序不同,像avr和stm32就是相反的,用时需要注意th与tl的顺序。
建议直接使用数组里的元素替代tl与th,x可以是个u16的指针,初始化的时候直接指向t,这样转换起来几乎不花时间。
此法在读16位以上adc的spi时很方便,一个指针传过去,spi寄存器的值直接写到u8的数组里,读的时候强制类型转换成u16就行了。也可以把一个u16数的地址转换成u8的当函数变量,函数结束后u16数的值就是所需的了。用法多样,很灵活。
特别是有24位、或者多路数据的时候,特别节省运算时间。 【29楼】 ilawp
你的方法其实就是共用体(联合体)的变型了。
union uni2Byte
{
unsigned int all;
unsigned char t;
};
然后
union uni2Byte x;
x.t=TH1;
x.t=TL1;
x.all就是所求的16位数。(同样要注意大小端问题)
这种方法效率是最高的,数据量大时可以这么用,数据量不大感觉写的麻烦。 简单点,就是个联合体,如楼上所说,最简单
typedef union LONGDATA{ // Access LONGDATA as an
unsigned long result; // unsigned long variable or
unsigned char Byte; // 4 unsigned byte variables
}LONGDATA;
static LONGDATA rawValue;
rawValue.Byte = 0x00;
rawValue.Byte = (unsigned char)ADC0H;
rawValue.Byte = (unsigned char)ADC0M;
rawValue.Byte = (unsigned char)ADC0L;
mV = rawValue.result / 6710; // Because of bounds issues, this union
{ /*定义占用一个字的共用体,可以实现字或两个字节的存取*/
uint16_t d16;
uint8_td8; //d8存放dat16低位,d8存放dat16高位
}word; 回复【17楼】shark
真是不嫌麻烦,我都用 (th1*256+tl1) ,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------
th1是8位的,不会溢出? 回复【33楼】rube 永丰庵
回复【17楼】shark
真是不嫌麻烦,我都用 (th1*256+tl1) ,还没遇到哪个编译器能傻到连乘2^n都真的产生乘法指令.
-----------------------------------------------------------------------
th1是8位的,不会溢出?
-----------------------------------------------------------------------
又不把结果放入th1 我五楼就说了这么写只是读取TH1的值,并没有操作TH1,很多人都认为TH1是8位的,怎么移位都是8位的。 http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560226ZYKA8O.JPG
(原文件名:447.JPG) 注意这三行.尤其是第三行,就是 (TH1<<8) , 结果等于 0
000003: 0422MOV A, 0x22 [ 34]
000004: 0050MOV 0x10, A [ 16]
000005: 00D0CLR 0x10 [ 16]
但是1楼的写法编出来的代码没问题 7楼的写法
temp=((unsigned short int)(TH1<<8))|TL1;
编出来的代码
000003: 0422MOV A, 0x22 [ 34] TH1
000004: 0052MOV 0x12, A [ 18]
000005: 00D2CLR 0x12 [ 18] <<8
000006: 0412MOV A, 0x12 [ 18] (unsigned short int)
000007: 0052MOV 0x12, A [ 18]
000008: 00D3CLR 0x13 [ 19]
000009: 0423MOV A, 0x23 [ 35] TL1
00000A: 0050MOV 0x10, A [ 16]
00000B: 00D1CLR 0x11 [ 17]
00000C: 0410MOV A, 0x10 [ 16] |
00000D: 0252OR 0x12, A [ 18]
00000E: 0411MOV A, 0x11 [ 17]
00000F: 0253OR 0x13, A [ 19]
000010: 0412MOV A, 0x12 [ 18] temp=
000011: 0060MOV 0x20, A [ 32]
000012: 0413MOV A, 0x13 [ 19]
000013: 0061MOV 0x21, A [ 33]
000014: 0012RET
和2楼的结果一样,是错的
"我五楼就说了这么写只是读取TH1的值,并没有操作TH1,很多人都认为TH1是8位的,怎么移位都是8位的。 "
回家好好把C语言的型(type)及型转换(type casting)看一遍,就会知道为什么 "很多人" 都说 "TH1是8位的,怎么移位都是8位的" 学习! 【38楼】 avr741
7楼应该是个笔误,你试试这个(请参考15楼的写法)
temp=(((unsigned short int)TH1)<<8)|TL1;
如果这样还不行的话,说明你的译编器OUT了。
叫我回去看书的你是第二个,请推存本书能够说明我这句话是错的
"我五楼就说了这么写只是读取TH1的值,并没有操作TH1,很多人都认为TH1是8位的,怎么移位都是8位的。 " to【40楼】 hsztc
--------------------------------
印象中按C语言标准,移位操作前char应自动转换int然后再执行,所以
TH1<<8的值应该等价于 ((int)(TH1))<<8 ,但不排除某些8位机编译器不做这个转换(比如36楼的EMC的编译器),所以后者可以算作加了一个保险吧。 这个编译器我试过了, 15楼的 和 17楼的TH1*256+TL1 都是正确的, 这个编译器是这家公司的网站上目前最新的版本(2009年的)
不是这个编译器OUT, 也不是我牛,能让IAR出错(16+16时)
而是你在2楼和7楼的写法就是有潜在的问题!
我想任何一本C语言的书都会提到 型转换(type casting) 而且还有分 指示性(强制性的)和非指示性(自动的)型转换
你的问题就在于 "非指示性(自动的)型转换" 出了问题, 这个你自己回去去看书吧 网上也找得着这类的说明
以你上面的态度,我提醒你的已经够多了 【42楼】 avr741
我说的有错吗?请回答我40楼问题,如果temp=(((unsigned short int)TH1)<<8)|TL1;
这样写还有问题的话,这编译器真OUT了,切出图来看看?
不过有一点我真得认错,temp=(TH1<<8)|TL1; 还真有编译"出错"的编译器,确实有不一样的情况,长见识了。
IAR并没有出错,出错的是你,IAR只是对你写的内容进行编译,只能说编译的结果和你想要的不一样而以。
如果你表达清楚了你的意思,IAR就能编译出你所要的结果。
每个方法都有特定的局限性,如果不知道怎么灵活应用,只会照搬的话难免出错。
出错了又知道怎么去改,就出来大叫,这样会让我很郁闷,还得花大把时间跟你解释,
如果你知道哪里有问题你直接说出来就行了,把你可行的方法说出来,而不是举反面例子。
至于你为什么叫我看型类转换我真搞不明白。
关于态度问题,你应该得反省下,随便叫人回家看书是不尊重人的,你去坛里转转有几个敢这么说别人的。 "请回答我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楼的算法就有局限性? 自己出了问题还怪别人"不知道怎么灵活应用,只会照搬"?
"出错了又知道怎么去改,就出来大叫," 应该是少了一个"不""出错了又不知道怎么去改"
看看我的原文 "注意我红线标出来的警告,那又是另一个问题" 这只是我提醒你还有别的问题
你当真以为我是天堂里的猪脑袋,不知道怎么改吗? 来求你告诉我怎么改吗?
"关于态度问题,你应该得反省下,随便叫人回家看书是不尊重人的,你去坛里转转有几个敢这么说别人的。 "
因为这是很基本的问题,书上都有,叫你回家看书的我也不是第一个(这是你说的,我也不知道还有谁也叫你回家看书)
我只是提醒你的写法可能会有问题,那你动不动叫我截图出来给你看,动不动叫我花时间去找编译器,就不会不尊重人吗? "如果你知道哪里有问题你直接说出来就行了,把你可行的方法说出来,而不是举反面例子。 "
"至于你为什么叫我看型类转换我真搞不明白。"
其实真正的问题,我在这个主题其中一个贴子已经解释过了
可能你看我积分很少,认为我所说的话都是没价值的,是不可信的,甚至是错的,所以你根本不用心看
才会叫你回家看书,因为书上说的,你总不能不信吧! hsztc 并没有理解数据类型转换,而且太不谦虚。
avr741 很有耐心。
简单的说有些编译器能自动转换数据类型,但不是所有的编译器都会这么做,TH1<<8的结果是什么取决于TH1的数据类型!
之所以 TH1<<8 或 TH1*256 能得到正确的结果是因为编译器自动进行了转换。 1楼最好。
2楼的写法垃圾。
鉴定完毕。 回复【47楼】aviator
hsztc 并没有理解数据类型转换,而且太不谦虚。
avr741 很有耐心。
简单的说有些编译器能自动转换数据类型,但不是所有的编译器都会这么做,th1<<8的结果是什么取决于th1的数据类型!
之所以 th1<<8 或 th1*256 能得到正确的结果是因为编译器自动进行了转换。
-----------------------------------------------------------------------
*256应该比较安全,因为256已经超过u8的范围了,编译器只要不傻就会自动转换成int来算 【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
学学人家是怎么说的。积分不是问题,你看看这个前辈积分多少,不过积分少的来找事的确实会多点。 先上一张截图,是别的网站的,部分ID已隐去
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560413JVHXD5.JPG
(原文件名:60elder.JPG)
先看看别人是如何立马认错的,再看看你自己的态度又是如何
看来你还是没有找到问题的关键,只会在什么7楼,15楼,40楼,编译器的效率很低上面作文章 【5楼】 hsztc
积分:1112
派别:
等级:------
来自:福建省
【3楼】 chess01 =CHESS
是吗?
你为什么不去写一下再说呢?
我并没有改变TH1和TL1的值,我只读取它们的值。
==========================================
不是搞人身攻攻击哈,你在2楼的写法想都不用想,它就是错的。
TH1与TL1是没变,但var=(TH1<<8)这个var始终是0 回复【52楼】MZ_Guo
不是搞人身攻攻击哈,你在2楼的写法想都不用想,它就是错的。
th1与tl1是没变,但var=(th1<<8)这个var始终是0
-----------------------------------------------------------------------
看看C99的标准是怎么说的:
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560500SZ6B1Z.JPG
(原文件名:shift.JPG)
<< 操作符要求两个操作数都是integer类型的,如果不是则自动提升为integer类型。
所以TH<<8和((int)(TH))<<8 是等价的,不过某些编译器没有遵循标准。 "<< 操作符要求两个操作数都是integer类型的,如果不是则自动提升为integer类型"
"所以TH<<8和((int)(TH))<<8 是等价的,"
这个是对的!
"不过某些编译器没有遵循标准。 "
如过你是说EMC的话, 这个不是事实
既然你遇到问题已经有去查书了,比起 hsztc 好太多,我就提醒你看一下我在21楼的
"既然你的前提是默认值是16位,如果碰到默认值不是16位整型的C编译器呢? 也许是8位的,也许是32位的 "
应该可以解释你在41楼的疑惑 【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的这个软件,生成一堆堆的汇编又是错的。
所以遇到偏冷的编译器的时候还是老老实实的写全代码。
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560509HRH7SK.PNG
(原文件名:iarfor511.PNG)
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560510A7B4VL.PNG
(原文件名:iarfor512.PNG)
这是IAR FOR 51的结果,红色框内为生成的(temp=(TH1<<8)|TL1;)
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560511RFHTN8.PNG
(原文件名:keil1.PNG)
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560512C6TMRV.PNG
(原文件名:keil2.PNG)
这是KEIL C51的结果,红色框内为生成的(temp=(TH1<<8)|TL1;)
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560513A9ZQPK.PNG
(原文件名:icc1.PNG)
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560514SY1SKE.PNG
(原文件名:icc2.PNG)
这是ICCAVR的结果,红色框内为生成的(temp=(TH1<<8)|TL1;)
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560515AOG5GY.PNG
(原文件名:iarforavr1.PNG)
http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560516AB7OT5.PNG
(原文件名:iarforavr2.PNG)
这是IAR FOR AVR的结果,红色框内为生成的(temp=(TH1<<8)|TL1;) 打个注解:刚回来看到有回复了,所以在这边写回复,没想到写的时间长了点,当时并没有看到53楼和54楼,提交后才看到的。 回复【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类型,其它的是程序员的责任。 回复【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 这个不是完全对的 粗略的看了下楼上各位的说法:
我也乱说几句。
(1)首先 很重要一点就是avr741 说的, 就是byte是8位的。但是其余的像int、long int 这些玩意到底是几位的 不同编译器可能就会不一样 所以 如果哪位的解释没有主意到这点那么你的解释就可能让别人误解
(2)有人提到 C99标准。还引用了原文。 这个没有必要研究。编译器也没有必要完全遵守C标准。要清楚,我们搞的是嵌入式的编译器 ,我们的C语言和C发明者发明的C语言的是有区别的。
比如说 一般c语言说讲 指针运行会比数组快。但是,比如KEIL C51编译器中,数组要比指针快!
(3)有人提出要用联合体。我个人非常不喜欢用联合体,因为可能会带来大小端问题移植差
(4)可以考虑用 那个H1 * 256 + L1
(5)一般来讲移位 和 “|” 一起用 不会出现什么问题
但要特别注意: 移位 和 “取反~”一起用 在“不用的位数”的片子下 特别容易出问题
(6)依靠编译器进行自动转换 这种做法个人感觉比较不放心还是强制转转 比较安心 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语言,我们吵了几天,完全不对题 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,也会溢出,变成零,如何解释,请指教。 恩,用指针拼合最快了,直接就编译成MOV指令了,4-6周期搞定。 恩,用指针拼合最快了,直接就编译成MOV指令了,4-6周期搞定。 http://cache.amobbs.com/bbs_upload782111/files_29/ourdev_560572DI992J.JPG
(原文件名: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 的原因,才不容易搞错 回复【61楼】shark
-----------------------------------------------------------------------
你说的对 不过C发明者说 C规则是给编写编译器的人看的所以没有太多时间的话 还是不看为妙
多花点时间在别的方面 比如刚出的CM3内核上
这个不会过时 有用 看看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_SRcpu_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 != (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 = 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 = (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 = '?';
pevent->OSEventName = OS_ASCII_NUL;
#endif
OS_EventWaitListInit(pevent);
*perr = OS_ERR_NONE;
return (pevent);
} 将高八位数据按照无符号数乘以8后与低八位数据相加。 一段程序引发的血案。。~~其实楼主的问题早解决了,~~ 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. 靠,都在这里打口水仗,自己直接上计算机编程序模拟一下就知道了啊,在这里问还浪费不少时间。 这个我都是用指针操作!也很方便! 收益匪牵。 联合体与结构体共用。。。即可以整体操作,也可以单独操作! 唉
unsigned int timer1;
EA=0;
do{
timer1 = (unsigned int)(TH1 << 8) | TL1;
}while ( (timer1 >> 8 ) != TH1 );
EA=1; 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,乘法没出现,更没有移位,只是简单的数据移动。 最简单的方法 C语言中 一个UNION 就 搞定! 学习了,呵呵! 我终于相信了金庸小说中的华山论剑舞林大会,高手对决就是不一样,收益匪浅啊。其实这样的讨论多一些还是好的。 ......
這裡的人很強大... 16: unsigned int temp;
17:
18: ((unsigned char*) (&temp)) = TH1;
C:0x0B60 858D30 MOV 0x30,TH1(0x8D)
19: ((unsigned char*) (&temp)) = 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 高手有时候也会遇到更高的高手,呵呵。都消消火,心平气和说清楚不就结了,花这么多口水盖这么高的楼。。。 联合不可靠,不同的编译器int高低字节顺序是不同的,这样代码移植时会有麻烦。int = (((int)char_H)<<8)|chat_L 应该可靠的。 不记得在哪里看到的如下的声明了,个人觉得还是比较好用的
#define MakeWord(a, b) ((WORD)(((BYTE)(a)) | ((WORD)((BYTE)(b))) << 8))
#define MakeDWord(a, b) ((DWORD)(((WORD)(a)) | ((DWORD)((WORD)(b))) << 16))
另外关于数据类型转换还是自己做的比较好,以后再阅读代码也比较省心。即使更新了单片机,程序还可以跑起来。 很多人吃过亏回复【81楼】zhiwei
高手有时候也会遇到更高的高手,呵呵。都消消火,心平气和说清楚不就结了,花这么多口水盖这么高的楼。。。
-----------------------------------------------------------------------
人之常情.站在越高的楼上越容易往楼下看风景,因为更高的楼已经很少了,所以看到更高的楼时,第一反应会认为那是幻影. 更认同 avr741 的观点。他的思路更多地考虑了程序的可靠性。也许这样写出来的程序会稍显冗长,多花一些时间输入,但是在调试的时候,就会体会到这样的时间花的值得。这更多地体现的是一种编程风格。
感觉 hsztc 更倾向于代码的简练和效率,个人觉得这种风格在一些资源及其有限的项目中会有价值。但是从日常的使用来说,不建议采用这种编程风格。尤其在一个产品生命和维护周期很长,会由不同的人来负责这些代码的情况下,这种风格的程序可能就会是一个 bug 的来源了。 回复【80楼】rainyss
-----------------------------------------------------------------------
你的最好 回复【80楼】rainyss
-----------------------------------------------------------------------
你的最好 a=ds1820rd();//取温度低8位
b=ds1820rd();//取温度高八位
tvalue=b;
tvalue<<=8;
tvalue=tvalue|a;//第八位和高八位合在一起 13楼正解! "
unsigned int temp;
temp=(TH1<<8)|TL1;
" 这个好用 看大家的讨论,学习很多,谢谢各位 51单片机只有pc与dptr寄存器才是16位的。你可以把高8位放dph然后地八位放dpl就构成16位dptr了。定时器16位能干啥? 看大家的讨论,学习很多,谢谢各位 都是高人,看帖学习
页:
[1]