Skip to main content

不断传播

随着 CODESYS Static Analysis 版本V5.0.0.0,代码的分析基于常量传播。恒定传播的结果用于各种检查。例如,它检查指针是否不等于 0,或者数组索引是否超出有效范围。

只需了解静态分析的工作原理及其局限性,您就可以有效地支持静态分析。

不断传播

静态分析尝试根据变量的用途来确定变量的值。

1. 例子
PROGRAM PLC_PRG
//Declaration
VAR
    x: INT;
    bTest: BOOL;
END_VAR
//Implementation
x := 99;
IF x < 100 THEN
    bTest := TRUE;
END_IF

在第 1 行的实现中,常量传播记录了值 99 对于变量 x 使用该值进行进一步分析。然后分析发现以下表达式 IF- 语句常量 TRUE 是。



局部执行恒定传播

仅在功能块中本地确定值。输入的传递方式无关紧要。函数调用的结果也是无关紧要的。

2. 例子
FUNCTION Func : BOOL
//Declaration
VAR_INPUT
    bText : BOOL;
END_VAR
//Implementation
IF bTest THEN
    Func := OtherFunc(TRUE);
END_IF


即使参数 bTest 被设定为 TRUE 在每次调用时,这对恒定传播没有影响。即使 OtherFunc(TRUE) 总是返回 TRUE,这对恒定传播没有影响。

只有临时变量才有初始值。

程序和功能块中的静态局部变量没有假定的初始值。这些变量保留上次调用时的值,因此原则上可以是“任何值”。

函数中的局部变量和临时变量在每次调用时都有一个初始值。常数传播用这个初始值进行计算。

3. 例子
PROGRAM PLC_PRG
//Declaration
VAR
    x: INT := 6;
    bTest: BOOL;
END_VAR
VAR_TEMP
    y : INT := 8;
END_VAR
bText := x < y;

变量 y 每次都会被执行 PLC_PRG 值为 8。变量 x但也不一定。因此,恒定传播仅用于 y 假设一个值,但不是为了 x

建议声明始终先写入然后读取的变量作为临时变量。



常数传播确定数值数据类型的值范围。

为了降低复杂性,为每个变量确定了具有上限和下限的值范围。

4. 例子
PROGRAM PLC_PRG
VAR
    x: INT := 6;
    bTest: BOOL;
    y : INT;    
END_VAR
//Implementation
IF bTest THEN
    x := 1;
ELSSE
    x := 100;
END_IF
IF x = 77 THEN
    y := 13;
END_IF

这里取值范围 [1..100] 是为变量确定的 x。结果,在第 7 行,比较 x = 77 不被识别为常量表达式,因为 77 是在数值范围之内。



重复出现的复杂表达式不会被识别为同一变量。

复杂表达式可能没有分配值。如果这样的表达式多次出现,那么引入辅助变量会很有帮助。

5. 例子
PROGRAM PLC_PRG
VAR
    x: DINT;
    py : POINTER TO INT;
    y : INT; 
    testArray : ARRAY [0..4] OF DINT;   
END_VAR
//Implementation
IF py^ >= 0 AND py^<= 4 THEN
    x := testArray[py^];
END_IF
y := py^;
IF y <= 0 AND y <=4 THEN
    x := testArray[y];
END_IF

在第 2 行,尽管检查了指针指向的区域,但由于可能通过指针访问某个值,因此会发出错误。如果首先将该值复制到局部变量中并检查其范围,则常量传播可以确定该变量的值范围,并允许访问第 7 行的数组。



分枝

对于分支,单独计算各个分支。然后将各个范围中的值范围组合起来形成新的值范围。

6. 例子
//Implementation
IF func(TRUE) THEN
    x := 1;
ELSE 
    x := 10;
END_IF

IF func(FALSE) THEN
    y := x;
ELSE
    Y := 2*x;
END_IF

6号线, x 有范围 [1..10]。第 11 行之后, y 有取值范围 [1..20];这是两个值范围并集的结果 [1..10][2..20]



状况

7. 例子

条件可以限制代码块中变量的值范围。可以组合多个条件。互斥条件也可能导致空值范围。

IF y > 0 AND y < 10 THEN
    x := y;
ELSE
    x:= 0;
END_IF
IF x < 0 THEN
    i := 99;
END_IF

y 的取值范围 [1..9] 第 2 行。这会得出值范围 [0..9] 为了 x 第6行。结合条件 x < 0,这会导致一组空的可能值 x 第 8 行。该代码无法访问。静态分析将报告该情况 x < 0 总是返回 FALSE 在此刻。



循环播放

常量传播将循环代码,直到循环中变量的值不再改变。假设循环可以运行任意次。到目前为止确定的值与之前的值相结合。在循环内改变的变量具有连续增长的范围。这里,常数传播并不采用所有可能的范围值,而是仅使用代码中出现的限制以及值 0、1、2、3 和 10,因为这些通常是相关的。

8. 例子

描述该过程的最简单方法是通过示例:

PROGRAM PLC_PRG
VAR
    x: DINT;
    i : DINT;
    y : DINT;
END_VAR
//Implementation
x := 0;
y := 0;
FOR i := 0 TO 5 DO
    x := x + 1;
    y := i;
END_FOR

常量传播了解有关循环的以下信息:

i, x, 和 y 在第一次执行循环开始时为 0。条件 i <= 5 适用于循环中的代码。条件 i > 5 适用于循环后的代码。

对于循环中变量的值,常数传播确定以下值:

i

x

y

[0..5]

[0..MAXDINT]

[0..5]

具体来说,经过以下中间步骤:

经过

i

x

y

1

0

[0..1]

0

i 初始化为0; y 总是获得与 i 相同的值。

2

[0..1]

[0..2]

[0..1]

6

[0..5]

[0..6]

[0..5]

一、范围 [0..6] 实际上计算的是 i。然而,据了解, i < 5 是一个条件。因此,循环中代码的值仅限于该值。

7

[0..5]

[0..7]

[0..5]

10

[0..5]

[0..10]

[0..5]

x 越来越多地增加。从 10,但是,该值被“四舍五入”为 MAXINT

11

[0..5]

[0..MAXDINT]

[0..5]

MAXDINT + 1 结果是 MAXDINT

截至11日

从第11遍开始,循环中的值不会改变。传播结束。

此外, i = 6 适用于该循环之后的代码。范围 [0..6] 在循环中确定,并与条件结合 i > 5,结果恰好是值 6。