CODESYS开发教程14-指针使用

news2024/11/26 13:43:24

在写完《长字符串处理》以后,好长时间也没想到写什么内容好,前几天发现好像没有介绍过指针,那么今天我们的教程重点是介绍CODESYS中指针的使用。指针可以说算是C语言的精髓之一,有很多的优点和方便之处,但是同时也是个超级大坑(优点和缺点从来都是一体两面的~~)。在绝大部分时候,指针属于那种完全可以不用的类型,但是了解一下总是好的(就是喜欢学一些奇奇怪怪的用不着的知识😊)。本次教程对指针的基本概念、类型及使用方式,还有CODESYS的绝对地址映射做一下简单的介绍。

一、什么是指针

指针就是存储对象的内存地址的变量。内存地址就是内存的编号。如果把内存空间比喻成一家酒店,那么内存地址就是房间号。数据是存储在内存中的,住酒店的客人是住在一个个房间里面一样。取数据的指针就是取数据的地址,也就是酒店的房间号。

在CODESYS里面是地址是可以用类似%MWx(x=0~n)来表示。例如:

%MW10 := 123;

数据123存储在内存地址%MW10处,10就是地址。如果定义一个指针指向10,那么就可以理解为这个指针的值就是10。W表示的WORD类型,就是指针指向的地址的空间大小,类似与酒店房间的不同类型,如标准间、大床房、总体套房等等。

指针和数组一样,也是一种变量类型,因此需要先定义后使用。在CODESYS中,指针的定义方式如下:

pa : POINTER TO INT;

a : INT := 1;

pa:=ADR(a);

变量pa 定义了一个指向 INT类型的指针。POINTER TO 是定义指针的关键字,INT是指向的数据类型。

二、指针的类型及定义

1. Pointer to

指针的声明格式如下:

<pointer name>: POINTER TO <data type | data unit type | function block>;

在CODESYS中,指针是一个DWORD类型的值(不区分32位还是64位平台)。

取值操作符^:获取指针指向对象的内容。如上图中,P1为变量D1的地址,而P1^为D1的值。

注意:由于I/O的具有访问限制,因此定义指向I/O的指针以后,在代码生成时编译器会提示“<pointer name >不是一个有效的赋值目标”。如果需要对I/O值进行操作,可以先将I/O值拷贝到自己定义的变量中,再进行指针操作。

2.指针的索引访问

CODESYS允许通过索引操作符[]来访问指针指向的变量类型,例如以前教程中提到的字符串STRING类型可以通过[]访问字符串中的单个字符。

指针所指向的变量类型决定了操作符[]的索引移动长度,例如

pInt : ARRAY[0..10] OF INT;

pInt[i]实际上是地址(pInt+ i * SIZEOF(INT))指向的值。

即索引i改变时,地址偏移的长度与数据类型INT长度相关。

对于STRING类型,由于单个字符的存储类型是BYTE,因此通过指针索引访问时返回的值是一个SINT类型,即字符的ASCII码。

str   : STRING:=’CODESYS’;

str[1]的值为79,即字符’C’的ASCII码。

对于WSTRING类型,其单个字符类型为WORD,因此通过指针索引访问时返回的值是一个INT类型,即字符的UNICODE码。

3.取地址操作符ADR

ADR()用于获取变量的地址。

与CoDeSys V2.3不同,您可以将ADR运算符与函数名称、程序名称、函数块名称和方法名称一起使用。因此,ADR取代了INDEXOF运算符。

使用函数指针时,可以将函数指针传递给外部库,但不能从CODESYS中调用函数指针。若要启用系统调用(运行时系统),必须为函数对象设置相应的对象属性(“构建”选项卡)。这句话的意思是函数指针是给CODESYS调用外部实现的函数功能的,在CODESYS内部不能使用函数指针调用内部函数。另外在使用系统调用功能调用外部命令时,需要预先设置调用对象的属性(我的理解大概是这样,忍不住要吐槽一下CODESYS的帮助文档,看不懂啊看不懂~~~☹)。

注意:

(1)不能用于给常量取地址。例如,ADR(9)会报C0131错误。

(2)使用在线更改时,地址的内容可能会发生变化。因此,指针变量可能指向无效的内存区域。为了避免出现问题,应该确保指针的值在每个周期中都会更新。

(3)不要将函数和方法的指针变量返回给调用者,也不要将它们分配给全局变量。函数和方法内部的变量是不会保存的,每次调用是会初始化为0,调用完成后应该是不存在了,因此将其内部变量返回是没有意义的。

4.Runtime指针监视函数CheckPointer()

用于在运行模式下监视指针的内存访问。该函数实际上是给用户提供了一个指针的监视接口,用户可以根据自己的需求实现对所用指针的检查。函数的模板如下:

// 声明部分,请勿修改

FUNCTION CheckPointer : POINTER TO BYTE

VAR_INPUT

        ptToTest : POINTER TO BYTE;

        iSize : DINT;

        iGran : DINT;

        bWrite: BOOL;

END_VAR

// 实现部分,请用户自行添加代码

CheckPointer := ptToTest;

该函数的输入参数含义如下:

ptToTest:指针的目标地址。

iSize:引用变量的大小,INT型。iSize的数据类型必须覆盖变量的维度范围。

iGran:参考尺寸的粒度,INT型。这是引用变量中包含的最大非结构化数据类型??

bWrite:访问类型,BOOL型,TRUE为写入,FALSE为读取。

CheckPointer函数通常应该检查以下情况:

(1)检查返回的指针是否引用了有效的内存地址。

(2)监视引用内存范围是否与指针引用的变量类型匹配。

如果这两个条件都满足,则返回指针。否则需要在函数中进行错误处理。

注意:

(1)为了保证监视功能正常运行,不要修改声明部分,但用户可以添加局部变量。

(2)THIS和SUPER指针不会触发Checkpoint()函数调用。

(3)对于3.5.7.40及以上的编译器版本,对于REFERENCE变量也可以使用Checkpoint()函数进行检查。

说实话,这个功能我也没用过。主要是在CODESYS里面使用ST开发大部分时候不需要用指针。必须要用的时候,一定是确保用法是正确的,所以一般是不做这个检查的。必须要做这个检查的使用环境,目前还没遇到过,所以这里就不举例了(讲这么多,其实就是懒,没别的原因~~😊)。

5.引用Reference to

引用是对象的假名,实际上是指针,可以指向各种类型的数据(bit除外)、结构体、功能块、函数和程序。

定义方式如下:

<identifier> : REFERENCE TO <data type>;

引用赋值:

<identifier> REF = <variable>;

引用变量可以直接访问引用对象的值,不必使用^操作符。

对于引用类型,编译器会进行类型安全检查,即检查两个类型是否一致,不一致会报错。而指针这不进行这种检查,需要用户自己确保使用正确。在运行时,指针的内存访问可以通过隐式监视函数CheckPointer()进行检查。

引用作为函数或功能块参数时,不需要ADR()来进行参数传递。

注意:

(1)对于3.3.0.40及以上的编译器版本,引用变量会初始化为0。

(2)对输入设备定义引用时,由于没有写访问权限,编译器会显示警告。正确的方式与指针类似,定义一个中间变量与输入设备关联,然后对该中间变量定义引用。

(3)可以使用__ISVALIDREF()检查引用是否指向有效值(非0值为有效)。

(4)与指针一样,对常量定义引用是无效的。

三、指针的使用

1.结构体或数组指针

aa   : ARRAY[0..9] OF INT:=[1,2,3,7(100)];

pa   : POINTER TO INT;

pa := ADR(aa);

b:=pa[2];

c:=pa^;

//c:=(pa+1)^; //报错

pa:=pa+SIZEOF(INT);

d:=pa^;

pa:=pa+1;

e:=pa^;

指针pa实际上指向数组aa的首地址,pa^实际就是pa[0],数组序号默认是从0开始。需要注意的是,直接对指针进行加减操作时会导致结果不可预知。上图中c的值为1,即p[0]。将pa的值加上一个INT类型长度后,d的值变为2,即p[1]。但是在pa上加1以后,e的值变为768。另外(p+1)^这种操作是不合法的,编译器会报错。

2.二级指针

二级指针是指向指针变量的地址。

index : INT:=10;

p : POINTER TO INT;

pt : POINTER TO POINTER TO INT;

p:=ADR(index); //p^值为10

pt:=ADR(p); ///p^^值为10

四、动态内存分配

要使用动态内存分配功能需要在Application里面开启。如下图:

相关操作函数

__NEW:为功能块或数组分配内存,成功后会返回指向相应对象的指针,失败则返回0。使用的时候应避免在两个任务中同时调用,要么只在一个任务中调用该操作,也可以使用信号量SysSemEnter()来避免__NEW的同时调用(可能会导致任务周期出现大的抖动)。

__DELETE:释放__NEW分配的内存。该操作没有返回值,内存释放后对应的指针被设为0。对于指向功能块的指针,CODESYS会在指针设为0之前调用功能块的FB_EXIT方法。

五、地址映射

在使用内存动态分配或指针的时候,地址本身的内容在实时运行时可能会改变。CODESYS提供了一套用于定义内存绝对地址的方式。形式如下:

%<memory range prefix><size prefix><number|.number|.number....>

主要用于表示从指定的地址开始取,具体使用多少个字节,由定义的数据类型决定。

(1)内存区域memory range prefix

I:输入内存,指输入设备或传感器,常用的如数字输入。

Q:输出内存,指输出设备或执行器,常用的如数字输出

M:控制器内存。??

(2)数据类型size prefix

X:位

NONE:位

B:BYTE,8位

W:WORD,16位

D:DWORD,32位

(3)示例

%QX7.5   //输出内存位置7.5,类型为BIT

%IW215  //输入内存位置215,类型为WORD

%MD48   //内存位置48,类型DWORD

iWr AT %IW0: WORD; //为变量指定地址

例如给%MD0赋值为10:

%MD0:=10;

现在有指针P指向%MD0,那么P的值就是%MD0。然后取指针P的值赋给%MD1,就是把指针P 指向的%MD0的值取出来,赋给%MD1,此时%MD1的值也为10。

地址的类型和范围受当前控制器的配置和设置影响。寻址位置与设备类型无关,只与所用数据类型有关,即字5总是用%IW5寻址,字节5总是用%IB5寻址。采用不同数据类型的寻址实际上是在操作同一片内存,只是计数的长度不同。不同数据类型的对应关系如下表所示:

从上表可以看到,D0包含B0-B3,W0包含B0和B1。修改%QW0的值会影响到QX0.0~QX0.7的值,因此使用时应避免出现重叠。

五、总结

指针虽然方便,但是CODESYS因为自身的原因,对指针的支持有限。像内存的动态分配,早期版本是不支持的,现在的版本虽然支持但也是有限制的,所以真正需要用到的时候又不太方便。大家要是问我对于指针有什么经验,那我只能说对于小白来说,能不用就别用。实在是要用,要高度警惕类型匹配和指针越界问题,因为实在是太容易出错了,而且错了也不容易察觉(高手当然是随便怎么玩都好~~~)。

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

原创不易,感兴趣的多支持!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1563208.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

普通Java工程可执行JAR两种打包方式探讨

文章目录 一、需求概述二、代码结构三、运行结果四、打包设置1. 一体化可执行包2. 带外部依赖lib的可执行包 五、打包运行1. 源码放送2. 打包执行3. 打包结果 一、需求概述 普通Java工程 docker-show 实现了定时打印docker应用信息&#xff0c;现在需要将其打包成可执行Jar部署…

SSM学习——Spring AOP与AspectJ

Spring AOP与AspectJ 概念 AOP的全称为Aspect-Oriented Programming&#xff0c;即面向切面编程。 想象你是汉堡店的厨师&#xff0c;每一份汉堡都有好几层&#xff0c;这每一层都可以视作一个切面。现在有一位顾客想要品尝到不同风味肉馅的汉堡&#xff0c;如果按照传统的方…

【LeetCode热题100】17. 电话号码的字母组合(回溯)

一.题目要求 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 二.题目难度 中等 三.输入样例 示例 1&#xff1a; 输入…

团体程序设计天梯赛-练习集 (L1-025 - L1-036)

天梯赛题解合集 团体程序设计天梯赛-练习集 &#xff08;L1-001 - L1-012&#xff09; 团体程序设计天梯赛-练习集 &#xff08;L1-013 - L1-024&#xff09; 团体程序设计天梯赛-练习集 &#xff08;L1-025 - L1-036&#xff09; 团体程序设计天梯赛-练习集 &#xff08;L1-03…

树与二叉树的应用试题

01&#xff0e;在有n个叶结点的哈夫曼树中&#xff0c;非叶结点的总数是( A ). A. n-1 B. n C. 2n-1 D.2n解析&#xff1a;哈夫曼树中只有度为0和2的结点&#xff0c;在非空二…

67、yolov8目标检测和旋转目标检测算法batchsize=1/6部署Atlas 200I DK A2开发板上

基本思想:需求部署yolov8目标检测和旋转目标检测算法部署atlas 200dk 开发板上 一、转换模型 链接: https://pan.baidu.com/s/1hJPX2QvybI4AGgeJKO6QgQ?pwd=q2s5 提取码: q2s5 from ultralytics import YOLO# Load a model model = YOLO("yolov8s.yaml") # buil…

spring boot3登录开发-3(2短信验证登录/注册逻辑实现)

⛰️个人主页: 蒾酒 &#x1f525;系列专栏&#xff1a;《spring boot实战》 &#x1f30a;山高路远&#xff0c;行路漫漫&#xff0c;终有归途 目录 写在前面 上文衔接 内容简介 功能分析 短信验证登录实现 1.创建交互对象 用户短信登录/注册DTO 创建用户登录VO…

harmonyOS的客户端存贮

什么是客户端存贮 在harmonyOS中,客户端存贮是指将数据存贮在本地设备以供应用程序使用; 注: 和feaureAblity搭配使用,content上下文的获取依赖该API如下: // 引入: import featureAbility from ohos.ability.featureAbility;// 使用: let content featureAbility.getConten…

Git Fork后的仓库内容和原仓库保持一致

Git Fork后的仓库内容和原仓库保持一致 ①Fork原仓库内容到自己仓库 ②将项目内容下载到本地 ③使用git命令获取原仓库内容&#xff0c;将原仓库的最新内容合并到自己的分支上并推送 下面从第三步开始演示~ 这里以码云上的若依项目为演示项目 ③使用git命令获取原仓库内容 …

NLP重要知识点:预训练模型【核心且详细】

本资料是NLP核心知识点的ppt!!!【文章较长,建议收藏】 本节课我们学习预训练模型。 前言 我们在学习词向量的时候,应该知道了多个产生词向量的方法,包括基于矩阵(词-词共现矩阵)分解的方法、基于语言模型(word2vec)的方法、以及结合二者优点的Glove模型等其他产生词…

10kV配电室在线监控改造技术方案

摘要&#xff1a;目前&#xff0c;我国经济高速发展&#xff0c;社会在不断进步&#xff0c;国家加大了农村低压配电网络改造升级投入&#xff0c;低压配电网供电可靠性及供电质量得到明显提升&#xff0c;但低压配电网络自动化运维水平及农村电网用电安全尚处于较低水平。低压…

opejdk11 java 启动流程 java main方法怎么被jvm执行

java启动过程 java main方法怎么被jvm执行 java main方法是怎么被jvm调用的 1、jvm main入口 2、执行JLI_Launch方法 3、执行JVMInit方法 4、执行ContinueInNewThread方法 5、执行CallJavaMainInNewThread方法 6、创建线程执行ThreadJavaMain方法 7、执行ThreadJavaMain方法…

【算法刷题day14】二叉树理论基础、递归遍历、迭代遍历、统一迭代

二叉树理论基础 题目分类 二叉树的种类 无数值两种&#xff1a;满二叉树 和 完全二叉树 有数值&#xff1a;二叉搜索树 1.若它的左子树不空&#xff0c;则左子树上所有结点的值均小于它的根结点的值; 2.若它的右子树不空&#xff0c;则右子树上所有结点的值均大于它的根结点…

14.Python网络通信

本章讲解如何通过Python访问互联网上的资源&#xff0c;这也是网络爬虫技 术的基础。 1 基本的网络知识 程序员在进行网络编程前&#xff0c;需要掌握基本的网络知识&#xff0c;本节会介绍 这些内容。 1.1 TCP/IP 在网络通信中会用到一些相关协议&#xff0c;其中&#xf…

备考ICA----Istio实验16---HTTP流量授权

备考ICA----Istio实验16—HTTP流量授权 1. 环境准备 kubectl apply -f istio/samples/bookinfo/platform/kube/bookinfo.yaml kubectl apply -f istio/samples/bookinfo/networking/bookinfo-gateway.yaml访问测试 curl -I http://192.168.126.220/productpage2. 开启mtls …

python对接百度云车牌识别

注册百度智能云&#xff0c;选择产品服务。 https://console.bce.baidu.com/ 每天赠送200次&#xff0c;做开发测试足够了。 在应用列表复制 AppID , API Key ,Secret Key 备用。 SDK下载地址 https://ai.baidu.com/sdk#ocr 下载SDK文件&#xff0c;解压&#xff0c;…

面试 五

一、设计模式 1、工厂模式 工程模式&#xff1a;在javascript中&#xff0c;工程模式的表现形式就是 一调用即可返回新对象的函数。 // 工厂模式 function person (name, age) {return { name, age} } const person1 person("tom", 18) const person2 person(&q…

Google DeepMind 大语言模型中的长形态事实性

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 论文标题&#xff1a;Long-form factuality in large language models 论文链接&#xff1a;https://arxiv.org/abs/2403.18802 论文的关键信息总结如下&#xff1a; 研究问题是什么&#xff1f;论文…

9proxy—数据采集工具全面测评

9Proxy数据采集工具Unlock the web with 9Proxy, the top residential proxy provider. Get unlimited bandwidth, affordable prices, and secure HTTPS and Socks5 configurations.https://9proxy.com/?utm_sourceblog&utm_mediumcsdn&utm_campaignyan 前言 在当今数…

【智能算法】蜣螂优化算法(DBO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2022年&#xff0c;Xue等人受到自然界中蜣螂生存行为启发&#xff0c;提出了蜣螂优化算法&#xff08;Dung beetle optimizer, DBO&#xff09;。 2.算法原理 2.1算法思想 DBO模拟了自然界蜣螂种…