我的上一篇技术帖探讨了《沿触发的4个问题》。本篇探讨整型数据的类型转换与比较。这2篇技术帖有个共同的特点:所探讨的问题都是基础知识,但是基础知识也并不简单,需要一些细心和耐心才能hold住,否则容易出现bug。下面开启正文。
由下图的反直觉结果引发本篇的讨论。(本帖所用博途版本是V19)

图1
变量tempUint是Uint类型(本篇中变量名都带有变量类型,下同),给个值65535。变量tempInt给个1。显然65535应该大于1。所以在第30行中,变量tempbool应为false才对,但是代码的第30行给出了相反的结果。
既然与我们预期的不同,那我们要仔细琢磨一下代码的第30行。要分析第30行代码,我们需要先了解3个基础知识:隐式转换、比较符号是有数据类型的、uint_to_int如何转换的。
一,隐式转换
我们首先看到第30行。在这里编译系统自动加入了类型转换。这种由编译系统加入的类型转换称为隐式数据类型转换。
加入类型转换后,效果相当于代码第32行。这里面有个问题。为什么编译系统把变量tempunit转换为int呢?为什么不转换为其他类型呢?这是因为在比较符号左侧是int类型,那么随之而来的是比较符号右侧的数值也被隐式转换为了int类型。
二,比较指令是有数据类型的
**比较指令的2侧的数据类型必须相同,才能作比较。**这是因为int类型的-1和uint类型的65535都是16#FFFF。到底按照什么标准进行比较呢?
图1中,第30行代码经过隐式转换后,比较符号(本例中">")两侧都是int类型,那么这个比较指令就是int类型的比较。
类似的在LAD语言中,比较指令也需要给出数据类型。如下图中是INT类型比较。

三,uint_to_int如何转换的
在图1中,我们观察代码第32行及其监控。
发现Tempuint值是65535=16#FFFF=int类型的-1。也就是说 UINT_TO_INT(65535)转换后的值是-1。
函数UINT_TO_INT将该函数的输入值COPY到了输出,输出的类型是INT。
我们掌握了以上3个基础知识,那么对于图1中代码30行和32行的结果就不奇怪了。
四,SCL中,比较的正确写法

图2
观察图2的第34行,得到了正确的结果。
在编写SCL语言比较语句时,当比较语句的2侧数值类型不同,那么我们可以通过提升数据类型的长度来避免出现错误的比较。
在34行我们把UINT类型(16位长度)显式转换为DINT(类型32位长度)。这种提升长度的转换不会更改数值本身。转换前是65535,转换后仍是65535。
**当比较符号2侧是不同长度的数据类型,那么比较符号的类型会选择长度更长的。**在34行中,比较符号的左侧是INT,右侧是DINT,那么比较符号就是DINT的比较。
但是数据长度总是有限的。整数最大就是64位整数。

图3
图3中,第36行ULINT是64位,是最大长度的整数,无法将ULINT类型向上提升长度了。所以第38行代码仍然会出现问题。这也是为什么编译系统在ULINT_TO_LINT下方给出黄色提示的原因,这在提示我们这句代码可能会出现问题。
五,FOR语句的情况
在for循环语句中,循环数、初值和终值也可能是不同的数据类型。
在for循环语句中,也存在比较指令。
所以在使用for指令时,也要小心行事。
结束语:
本篇讨论了整型之间的数据转换以及比较指令。这一篇和上一篇一样,都讨论了最基本的编程知识点。
最基本知识点虽然基本可是一点也不简单。如果忽视它们,甚至看不起它们,那么必然在程序中给我们找麻烦。就像为人处事,不要看不起任何人。
另外,整型数据类型的转换不是我这简短帖所能完全说清楚的。这里只是抛砖引玉,提出一个需要大伙注意的问题。如果各位有什么心得或者疑问,也可以在这里讨论。