Codesys数据结构:扩展数据类型之指针 Pointer 详解

CODESYS 指针使用 codesys指针一般有两种方式使用,pointer和reference两种方式,最后还介绍一个如何避免指针出错导致程序不运行的方法。 阅读详情
AI摘要

本文详细介绍了Codesys编程环境中关于指针的数据结构,包括地址描述、绝对地址的概念和表示,以及指针的定义、操作和应用。通过关键词'Pointer to'、'adr'和'^'解释了如何使用指针读取和修改变量值,并讨论了指针的类型大小、地址映射、指针保护和指针偏移。示例中展示了如何利用指针优化数组求和的函数实现。

1 地址描述

在内存中,每个字节都有一个编号,通过编号找到存储区(类似去1-407室 取快递,编号就是1-407,快递就是对应存储区),这个编号在这里我们取个名字叫做地址;当定义一个变量并为其赋值的时候,计算机会开辟一块空间用来存取变量值,在程序中一般是通过变量名来引用变量的值,实际上程序在编译的时候已经将变量名字转为变量的地址,即通过变量名找存储单元的地址,从而读取或修改存储单元的变量值;
在这里插入图片描述

2 绝对地址

(1)描述

在设备中比如PLC,已经提前定义好一部分地址的用途(比如地址(16#0080000~~16#008FFFF)只用于外部输入地址),
在Codesys中 I 、Q 、 M 表示设备的绝对地址区域,分别是输入地址区、输出地址区、中间地址区;

(2) 地址表示

格式:%<内存区域>(<大小>)<内存位置>

  • 内存区域 : I 、Q、M
  • 大小 : X(位)、B(字节) 、W(字)、D(双字)
  • 内存位置:数字

例如 下面的关系对照表

举例Value
%IB1输入区域B1的地址;
%IX1.2输入区域B1中位2的位地址;
%QD2输出区域D2的地址;
在这里插入图片描述
(3) 地址映射

%<内存区域>(<大小>)<内存位置> :只是表示从哪个地址开始取,具体取多少个字节,是由我们定义的数据类型决定;

dwTest AT %IB1 : DWORD;

表示 从输出区域字节B1开始取 4个字节(DWORD占四个字节)中的内容映射到dwTest变量中;

3 指针

(1)描述

指针就是地址,它可以是绝对地址,也可以是用户自定义变量的地址;
当定义指针的时候,必须定义指针的数据类型,因为指针指向的变量类型不同,而类型所占字节大小不同,所有如果仅仅知道地址不知道类型时,指针就不知道从当前地址读取多少个字节;

(2)关键字:“Pointer to” 、“adr” 、“^”
  • “Pointer to” : 用来定义指针类型变量;
piTest: pointer to dword;(*指向dword类型的指针*)
pbTest: pointer to bool;(*指向bool类型的指针*)
prTest: pointer to real;(*指向real类型的指针*)
paiTest: pointer to array[1..10] of int ;(*指向int类型数组的指针*)
apiTest: array[1..10] of pointer to int;(*int类型指针数组:存储10个指针,每个指针指向Int类型*)
  • “ADR” 用来获取变量的地址
  • “^” 用来读取指针变量中地址对应的数值
VAR
piTest : POINTER TO INT;
iTest  : INT := 1; 
iTest2 : INT := 0;	
END_VAR

piTest := ADR(iTest);(*获取变量piTest的地址,保存到piTest指针变量中*)
iTest2 := piTest^;(*取地址对应的存储单元数据,赋值给iTest2*)

在这里插入图片描述

(3)指针变量中值的含义
  • 每个地址对应一个byte存储单元,即每个byte都有一个独立的地址
  • WORD\INT 等16位数据类型包含2个byte,其地址用第一个byte的地址表示;
  • dowrd\dint等32位数据类型包含4个byte,其地址用第一个byte的地址表示,以此类推;
  • 指针变量中的值代表某一个byte地址,指针的类型决定了是指向以这个byte开始,连续多少个字节;

在这里插入图片描述

  • 图中1000指的是第一个byte的地址,1001指的是第二个byte的地址,以此类推;

(1) 每个地址对应的空间是一个byte,byte中的每一位bit不具备单独的地址,如下图所示,取输出地址区第1个字节中每一位的地址,运行查看都是同一个值,这个值就是这个字节的地址;

VAR
	bBool_0 AT %QX0.0 : BOOL;
	bBool_1 AT %QX0.1 : BOOL;
	bBool_2 AT %QX0.2 : BOOL;
	bBool_3 AT %QX0.3 : BOOL;
	bBool_4 AT %QX0.4 : BOOL;
	bBool_5 AT %QX0.5 : BOOL;
	bBool_6 AT %QX0.6 : BOOL;
	apBool : ARRAY[0..7] OF POINTER TO BOOL;//指针数组
END_VAR

apBool[0] := ADR(bBool_0);
apBool[1] := ADR(bBool_1);
apBool[2] := ADR(bBool_2);
apBool[3] := ADR(bBool_3);
apBool[4] := ADR(bBool_4);
apBool[5] := ADR(bBool_5);
apBool[6] := ADR(bBool_6);

在这里插入图片描述

  • bBool AT %QW0 :BOOL;
    对于布尔变量,如果未指定单个位地址,则会在内部分配一个字节。bBool的值更改会影响从QW0.0到QW0.7的范围。
  • bBool AT %QW0.1 :BOOL ;
    布尔变量声明,其中明确指定了单个位地址。bBool只影响QW0.1的值
(4)指针类型大小

指针类型大小为8个字节,和指向的数据类型无关,如下图所示;所以指针类型变量可以表示(2^64-1) 中不同的数,每一个数代表一个byte地址,也就是可以表示(2^64-1) 个byte内存空间大小;

VAR   
piTest: POINTER TO DWORD;(*指向dword类型的指针*)
pbTest: pointer to bool;(*指向bool类型的指针*)
prTest: pointer to real;(*指向real类型的指针*)
paiTest: POINTER TO ARRAY[1..10] OF INT ; (*指向int类型数组的指针*)
iSize  :ARRAY[0..3] OF  UINT;
END_VAR

iSize[0] := SIZEOF(piTest);
iSize[1] := SIZEOF(pbTest);
iSize[2] := SIZEOF(prTest);
iSize[3] := SIZEOF(paiTest);

在这里插入图片描述

sizeof 返回变量所占空间的字节数

(5)指针类型的地址

指针类型的变量也是变量,每个变量都有自己的地址;
如下图所示:

  • piTest中的值是dwTest的地址
  • ppTest中的值是piTest的地址;
  • ppTest^ : 获得的是dwTest的地址
  • ppTest^^ : 获得的是dwTest变量的值,等价于 piTest^
VAR
ppTest: POINTER TO POINTER TO DWORD;  
piTest: POINTER TO DWORD;
dwTest : DWORD := 100;
END_VAR

piTest := ADR(dwTest);
ppTest := ADR(piTest);

在这里插入图片描述

在这里插入图片描述

(6) 地址映射
  • 指针的值(变量的地址)可以知道从那块区域取数据
  • 指针的类型可以知道取多少个字节数据;
  • 取的数据要和指针的类型一一映射

首先定义一个结构体

TYPE DUT :
STRUCT
	bTest1 : BOOL;(*1个字节*)
	bTest2 : BOOL;(*1个字节*)
	iTest  : INT;(*2个字节*)
	diTest : DINT;(*4个字节*)
END_STRUCT
END_TYPE

进行测试

VAR
 abyTest :ARRAY[0..7] OF BYTE := [1,0,2,0,7,0,0,0];
 pdutTest: POINTER TO DUT;
END_VAR

pdutTest := ADR(abyTest[0]);

在这里插入图片描述
其原理如图,变量pdutTest的值是 abyTest[0]的地址,然后就从abyTest[0]开始,取pdutTest指向DUT数据类型大小的数据,DUT为8个字节;也就是取abyTest[0]到abyTest[7]中的内容(因为数组的物理地址是连续的)映射到结构体DUT中;
在这里插入图片描述

(7) 指针保护
  • 指针没有保护,如果指针指向的位置是不可知的,因为指针变量的值是别的变量的地址,通过指针访问修改了一个不确定含义的地址,结果是不可知的;
VAR
 pdutTest: POINTER TO INT;
END_VAR

pdutTest :=16#002341234;(*随便赋值,16#002341234地址不知是哪个变量地址*)
  • 指针默认值是为0,意味着空指针
VAR
 pdutTest: POINTER TO INT;
END_VAR

在这里插入图片描述

  • 指针没有类型保护
    例如用一个INT类型指针,指向BOOL变量地址不会报警。
    一个BOOL变量会占用一个字节空间,其变量值取决于字节最低位的值;如果修改其他位(比如第二位)的值为1,BOOL变量会怎么样呢 ?
    在这里插入图片描述
    代码验证
VAR
 bTest  : BOOL:= TRUE;
 pbyTest: POINTER TO INT;
END_VAR

pbyTest := ADR(bTest);(INT型指针 指向BOOL类型地址)
pbyTest^ := 2;(*通过指针,把BOOL变量第二位置为1*) 

在这里插入图片描述

(8) 指针偏移:下标([])和加减操作符,可以控控制指针的偏移

(1)加减操作符方式

VAR     
  piTest : POINTER TO INT;
  aiTest : ARRAY[1..10] OF INT :=[1,2,3,4,5,6,7,8,9,10];
  iTest  : INT;
END_VAR

(*获得数组 aiTest[0]的地址,等价于piTest := ADR(aiTest[0])*)
piTest := ADR(aiTest);
(*获得数组 aiTest[1]的地址,需要当前地址偏移2个Byte地址,因为一个INT占2个byte*)
piTest := piTest + 2;
iTest  := piTest^;

在这里插入图片描述

(1)通过下标的方式:它进行了2部分工作,第一步是进行地址偏移,第二步取偏移后地址对应存储区的变量值;

VAR     
  piTest : POINTER TO INT;
  aiTest : ARRAY[1..10] OF INT :=[1,2,3,4,5,6,7,8,9,10];
  iTest  : INT;
END_VAR

(*获得数组 aiTest[0]的地址,等价于piTest := ADR(aiTest[0])*)
piTest := ADR(aiTest);

(*1 地址偏移:地址偏移量的计算方法是 下标中的数字n * sizeof(piTest所指向的数据类型),在这里是  1 * sizeof(int) = 2*)
(*2 取新地址对应存取区的变量值*)
iTest := piTest[1];

在这里插入图片描述

(9) 应用举例

写一个求可变数组求和的函数(数组是可变,最大数组长度位10000,最小为1)

  • 写法1:
FUNCTION POU : LINT
VAR_INPUT
	aiTest : ARRAY[1..10000] OF INT ;(*传入外部数组所有数据*)
    iNum   : INT;  (*外部数组长度*)
END_VAR
VAR
  i :INT;
END_VAR

(*求和计算*)
FOR i := 1 TO iNum BY 1 DO
    POU := POU + aiTest[i];(*累加求和*)
END_FOR;
  • 写法2:–指针
FUNCTION POU : LINT
VAR_INPUT
	aiTest : POINTER TO INT ;(*传入外部数组首地址*)
    iNum   : INT;  (*外部数组长度*)
END_VAR
VAR
  i :INT;
END_VAR

(*求和计算方式1*)
FOR i := 1 TO iNum BY 1 DO
    POU := POU + aiTest[i]; (*取地址对应中的数据,不断累积求和*)
END_FOR;

(*求和计算方式2*)
FOR i := 1 TO iNum BY 1 DO
    POU := POU + aiTest^; (*取地址对应中的数据,不断累积求和*)
	aiTest := aiTest + SIZEOF(INT);(*指向数组中下一个INT型变量地址*)
END_FOR;


  • 比较说明
    写法2明显会开辟的空间小,指针类型变量占用8个字节,数组变量(ARRAY[1…10000] OF INT)占用10000*2=20000个字节,如果数组长度为百万,千万,其效果更明显;
    请添加图片描述
CODESYS开发教程14-指针使用 这是一篇写给新手的关于CODESYS开发环境的小白教程,一看就懂才怪😊...... 阅读详情

相关推荐

CODESYS开发教程6-关键字及变量类型

这是一篇写给新手的关于CODESYS开发环境的小白教程,一看就懂......

halps的专栏 2万+

codesys之指针调用数组及结构体

codesys指针使用 我们先定义一个指向INT的指针P,然后定义一个数组将指针指向数组首元素,就是取了数组首元素的地址。然后我们把指针指向的地址的数据取出来,赋给其他变量使用。^是取指针内容的意思,也就是把指针指向的地址的数据取出来。 定义: FUNCTION FUN_Git_CCU_VCU_Data : XK.CCU_VCU_INPUT VAR_INPUT END_VAR VAR p:POINTER TO INT; arr:ARRAY[0..5] OF INT:=[1,2,3,2(4)]; v

weixin_45787652的博客 1万+

CODESYS开发实战:指针与动态内存分配的高效应用

本文深入探讨了在CODESYS开发中如何高效、安全地应用指针与动态内存分配技术。通过将指针比作“酒店房间号”,文章生动解释了其作为内存地址间接访问器的核心概念,并详细介绍了指针定义、操作符、索引访问以及与引用(REFERENCE TO)的区别。重点阐述了使用__NEW和__DELETE进行动态内存分配以处理不定长数据(如动态数据包缓存器)的实战方法,同时强调了避免内存泄漏、线程安全等关键陷阱与最佳实践。此外,文章还讲解了绝对地址映射与指针结合,实现与硬件直接对话及高效内存操作的高级技巧,为开发者从静态编程思

weixin_29168813的博客 394

Codesys—指针变量的应用示例

Codesys下指针变量的理解和应用

原来你也__的博客 3341

CODESYS指针与引用全解析:为什么90%的开发者都用错了?

本文深入解析CODESYS中指针与引用的核心区别与正确用法,指出90%的开发者因混淆概念而导致的常见错误。文章重点剖析了绝对地址映射、动态内存分配的风险,并通过实战案例对比了指针的直接内存操作与引用的类型安全优势,旨在帮助开发者编写更稳定、高效的PLC控制程序。

sugar的博客 703

避开Codesys指针的坑:数组遍历、结构体访问中的5个常见错误及调试技巧

本文深入探讨了Codesys编程中指针操作的5个常见错误及调试技巧,重点解析了数组遍历和结构体访问中的陷阱。通过实际案例和代码示例,帮助工程师避免指针越界、类型不匹配等问题,提升工业自动化系统的稳定性和可靠性。

weixin_30516243的博客 403

Codesys 数据结构:扩展数据类型之引用 Reference 详解

REFERENCE(引用)是对指针的应用,内部也是指针;指针可以指向各种数据类型(bit除外),结构体,功能块,函数及程序,引用也同样可以。如果对codesys指针不太了解,可以参考上一篇博客优点1: 类型安全对于引用,编译器在分配引用时会检查两个类型是否一致,例如VAR_INPUT(*指针*)(*引用*)END_VAR(*正常:将BOOL类型地址给INT类型指针*)(*报警:将BOOL类型赋值给INT类型引用*)优点2: 传参写法简介。

codesys01的博客 3328

CODESYS结构体指针实战:如何像C语言一样优雅地操作复杂数据块

本文深入探讨了CODESYS中结构体指针的高级应用,帮助工业控制开发者像C语言一样高效操作复杂数据块。通过指针传递、嵌套结构体访问和模块化驱动设计等实战技巧,显著提升PLC程序的内存利用率和执行效率,特别适用于设备状态管理和通信优化场景。

weixin_30908103的博客 370

Codesys 数据结构: 扩展数据类型之bit类型详解

REFERENCE(引用)是对指针的应用,内部也是指针;指针可以指向各种数据类型(bit除外),结构体,功能块,函数及程序,引用也同样可以。如果对codesys指针不太了解,可以参考上一篇博客优点1: 类型安全对于引用,编译器在分配引用时会检查两个类型是否一致,例如VAR_INPUT(*指针*)(*引用*)END_VAR(*正常:将BOOL类型地址给INT类型指针*)(*报警:将BOOL类型赋值给INT类型引用*)优点2: 传参写法简介。

codesys01的博客 1073

CODESYS指针与引用全解析:何时用指针?何时用引用?

本文深入解析CODESYS中指针与引用的核心区别与应用场景,通过性能测试数据展示两者在函数参数传递、结构体操作等方面的效率差异,并提供工业自动化开发中的最佳实践方案,帮助开发者优化代码性能与安全性。

c7d8e的博客 214

Codesys引用数据类型详解:从概念到高级应用实战

在工业自动化编程中,数据结构与内存管理是构建健壮、高效控制程序的核心基础。理解数据在内存中的存储与访问原理,对于优化程序性能、实现复杂逻辑至关重要。其中,引用(Reference)作为一种高级数据抽象机制,其技术价值在于实现了数据的间接访问与高效传递,避免了不必要的数据拷贝,从而显著提升大型项目的执行效率与内存利用率。这一特性在需要处理动态数据、构建复杂软件架构或进行模块化设计的应用场景中尤为关键。本文聚焦于Codesys平台下的引用数据类型,深入解析其相较于指针的安全特性、生命周期管理及在函数参数传递、动

weixin_30425949的博客 508

CoDeSys入门实战一起学习(二十三):数据类型实战总结!选择技巧+内存优化

从标准数据类型、标准扩展数据类型,到自定义数据类型,我们用3篇文章讲透了CoDeSys的整个数据类型体系。在实际项目开发中,很多开发者不是“不会用”,而是“用不好”——比如选了不合适的类型导致内存浪费、使用指针/联合体时出现数据错乱、数组下标越界导致程序崩溃……——不盲目选择大类型(如用LINT存储0~100的数值),也不选择小类型导致取值范围不足,同时结合变量的。在实际开发中,数据类型的错误是最常见的编程错误之一,轻则编译报错,重则程序运行异常、设备故障,以下是。限定数值范围,软件钳位(如模拟量输出)

电工 1335

CODESYS开发实战:指针与动态内存分配的高级应用

本文深入探讨了CODESYS开发中指针与动态内存分配的高级应用,从基础概念到实战技巧全面解析。通过内存模型分析、数组与结构体操作、动态内存管理(__NEW/__DELETE)等核心内容,结合硬件地址映射和调试技巧,帮助工程师安全高效地使用指针优化程序性能。特别针对绝对地址映射、内存泄漏预防等关键问题提供实用解决方案。

weixin_26742753的博客 393

CoDeSys进阶:联合体、引用、指针等5种扩展类型实战解析

在工业自动化编程中,数据类型与内存管理是PLC开发者从基础迈向进阶的关键。联合体(UNION)允许同一段内存以多种类型解读,是通信报文解析的利器;而长时间(LTIME)以其64位纳秒级精度,解决了TIME溢出与高精度时间戳难题;宽字符串(WSTRING)则让中文等Unicode文本处理更加安全。此外,引用(REFERENCE)与指针(POINTER)作为传址操作的核心工具,在数据共享与底层操作中扮演重要角色。结合CoDeSys(IEC 61131-3)环境,本文从实际工程问题出发,讲解这5种标准扩展类型的语

weixin_30342363的博客 240

CODESYS指针型变量编程应用(配方)

什么是指针,指针的详细解释可以参看高级语言部分对指针的描述,这里不详细科普了。关于西门子的指针型变量应用,大家可以参看下面这篇博文:西门子PLC 间接寻址(指针)_RXXW_Dor的博客-优快云博客_plc间接寻址1、先讲下smart200PLC的间接寻址,200PLC借助& *实现指针操作 指针和FOR循环指令配合可以实现很多灵活的程序机构,这点大家自行体会。 2、下面讲西门子博途的间接寻址,由于博途支持很多复杂的数据结构,所以博途的编程也更加灵活,数组,结构变量等,大家不用间接寻址有时也能实现同样的功

RXXW_Dor的博客 3567

攻防世界GFSJ1184_welcome_CAT_CTF

由于它是 PIE 可执行文件,程序加载地址会随机化,这导致你在 GDB 调试时需要处理地址偏移(如 0x246d 变成 0x55555540246d)。:client 程序通过网络连接(get_nc() 和 get_flag(nc))与 server 通信,server 监听在端口 8888。:client 依赖外部共享库(如 libstdc++.so),因此运行时需要这些库存在系统中。程序就是wasd移动,走到不同标记(* $ @ )下方,输入j回车,会有不同反应。两个文件client和server。

拥抱AI的老粽子 1264

CoDeSys入门实战一起学习(二十一):联合体、长时间、宽字符串、引用、指针5种标准扩展类型,解决复杂编程问题

—自定义数据类型,详解数组、结构体、结构体数组、枚举、子范围,这些类型能让你根据项目需求“定制”数据类型,让程序结构更清晰、更易维护,比如用结构体封装一台电机的所有参数,用枚举定义设备的运行状态,敬请期待!——通过指针,可间接访问任意变量的内存,实现灵活的内存操作,是CoDeSys中最灵活也最危险的扩展类型(使用不当会导致内存错误)。,相当于给变量起了一个新名字,操作引用就等同于操作原变量——引用与原变量共享同一块内存,修改引用的值,原变量的值会同步改变。,就是专门的解决方案。

电工 1392

5张图,搞懂三方支付机构的“备付金账户”体系

本文将详细解析第三方支付机构各类备付金账户的功能定位、所承载的支付业务处理流程以及日常管理。

银行信息系统应用架构详解 2146

Codesys数据结构:扩展数据类型Any的探索

Any内部是一个数据结构体,在定义一个Any变量时,内部会转成其结构体,定义如下TYPE Any : STRUCT // 实际参数的类型 typeclass : __SYSTEM . TYPE_CLASS;// 指向实际参数的指针 pvalue : POINTER TO BYTE;// 指针指向的数据大小 diSize : DINT;END_STRUCTEND_TYPETYPE_CLASS是变量的数据类类型,对于用户自定义的数据类型或者功能块实例,其值是 TYPE_USERDEF;

codesys01的博客 2029

52页PPT智慧矿山数字化工业大数据平台建设方案

致力于为煤炭企业构建“全”、“统”、“通”、”智”的(大数据平台/数据中台)体系,基于“数字新基建”时代的数据价值思考,构建全域数字化矿区共享能力中心,助力煤炭企业实现数字化转型,打通底层系统之间数据壁垒,加强公司整体管理和安全生产系数,为运营提供数据统筹模型,实现重点数据实时监控和数据共享开放服务。综上所述,智慧矿山数据治理是一个系统性的工程,需要煤炭企业内各部门连同行业和政府监管部门通力协作,制定数据标准和管理规范,重塑煤炭企业数据架构和数据传输链路,打通智慧矿山数据壁垒,保障数据质量和数据安全。

zuoan1993的博客 1055

SAP 财务快速记账之—G/L Item Fast Entry

SAP FICO 运维解决方案

lijinbao171022的博客 1647

CoDeSys扩展数据类型实战:UNION、LINT、WSTRING、指针与引用

PLC编程中,基础数据类型(如BOOL、INT、REAL)在处理复杂协议解析、64位计数、Unicode文本及大数据高效访问时往往力不从心,导致数据拆解困难、计数器溢出、中文乱码等常见问题。CoDeSys提供了五种被低估的标准扩展类型——联合体(UNION)、长整型(LINT/ULINT/LTIME)、宽字符串(WSTRING)、指针(POINTER)和引用(REFERENCE),它们从内存映射、数值范围、编码表达和访问方式四个维度补足了基础类型的短板。理解这些类型的原理与适用边界,能够显著提升设备开发中数

weixin_29174385的博客 325

win10 离线安装.Net Framework3.5

起因,安装软件比如3dmax2014等需要.Net Framework3.5支撑,那么需要安装低版本的.Net Framework3.5 闲话少说。 1.下载 NetFx3.cab 链接: https://pan.baidu.com/s/124to7F3BOy4yAlY61OjbDg 提取码: kixu 2.将NetFx3.cab 放入 系统盘的windows目录下(示例 C:\Wi...

m0_37615458的博客 7723
上一篇: Codesys 数据结构:扩展数据类型之联合体(UNION) 类型详解
下一篇: Codesys 用ST语言读写XML文件说明 + 代码下载
林磊教育
博客等级 码龄3年 405粉丝 31原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值