变量引用

#include <iostream>

const float pi = 3.14f ;
float f ;

float f1(float r)
{
	f = r*r*pi ;
	
	return f ;
}
float& f2(float r)
{
	f = r*r*pi ;
	
	return f ;
}

int main()
{
	float f1(float = 5) ;
	float& f2(float = 5) ;
	float a = f1() ;
	float& b = f1() ;
	float c = f2() ;
	float& d = f2() ;
	
	d+=1.0f ;
	
	cout<<"a = "<<a<<endl ;
	cout<<"b = "<<b<<endl ;
	cout<<"c = "<<c<<endl ;
	cout<<"d = "<<d<<endl ;
	cout<<"f = "<<f<<endl ;
	
	return 0 ;
}

上面程序编译时不通过,存在引用错误,所以在这里详细解析下

解析:

  这里f1()函数返回的是全局变量f的值,f2()函数返回的是全局变量f的引用。

(1)代码第21行,正确。声明函数f1()的默认参数调用,其默认参数值为5。

(2)代码第22行,正确。声明函数f2()的默认参数调用,其默认参数值为5.

(3)代码第23行,正确。将变量a赋为f1()的返回值。

(4)代码第24行,错误。将变量b赋为f1()的返回值。因为在f1()函数里,全局变量f的值78.5赋给一个临时变量temp,这个temp变量由编译器隐式地建立,然后建立这个temp的引用b。这里对一个临时变量temp进行引用会发生错误。

(5)代码第25行,正确。f2()函数在返回值时并没有隐式地建立临时变量temp,而是直接将全局变量f返回给主函数。

(6)代码第26行,正确。主函数中都不使用定义变量,而是直接使用全局变量的引用,这种方式是全部四种中最节省内存空间的。但必须注意它所引用的变量的有效期,此处全局变量f的有效期肯定长于引用d,所以是安全的。否则,会出现错误。例如,将一个局部变量的引用返回,此时全局变量f的值为78.5。

(7)代码第28行,正确。将d的值加1.0,此时d是全局变量f的引用,因此f的值变成79.5 。


所以注释24和31行后,代码能正常运行,结果为:
A = 78.5 ;

B = 78.5 ;

D = 79.5 ;

F = 79.5 ;


下面程序中同样会出现参数引用的常见错误:(可以尝试着先找找看)

#include <iostream>
using namespace std ;

class Test
{
public:
	void f(const int& arg) ;
private:
	int value ;
};

void Test::f(const int& arg)
{
	arg = 10 ;
	cout<<"arg = "<<arg<<endl ;
	value = 20 ;
}

int main()
{
	int a = 7 ;
	const int b = 10 ;
	int &c = b ;
	const int &d = a ;
	
	a++ ;
	d++ ;
	
	Test test ;
	test.f(a) ;
	cout<<"a = "<<a<<endl ;
	
	return 0 ;
}


解析:

  把const放在引用之前表示声明的是一个常量引用。不能使用常量引用修改引用变量的值。

(1)代码第14行,错误。因为参数arg是一个常量引用类型的,所以arg的值在函数体内不能被修改。

(2)代码第21和22行,a被声明为整型变量,b被声明为整型常量。

(3)代码第23行,声明c为b的引用,错误。其原因是b为常量,而c不是常量引用。正确的方式应用为:

const int &c = b ;
(4)代码第24行,声明d为a 的常量引用,正确。

(5)代码第26行,变量a自增1,正确。

(6)代码第27行,d自增1,错误。d是常量引用,不能对d使用赋值操作。

从上面的分析可以看到,对于常量类型的变量,其引用也必须是常量类型的;对于非常量类型的变量,其引用可以是非常量的,也可以是常量的。但是要注意,无论什么情况,都不能使用常量引用修改其引用的变量的值。



<think>我们正在讨论CODESYS中的变量引用方法和规则。根据提供的引用,以下是关键信息: 1. 引用[1]提到CODESYS中访问变量(属性)无需添加引用路径的方法,并指向一篇关于面向对象编程的文章,其中提到以信号发生器功能举例。 2. 引用[2]介绍了CODESYS编程基础,包括数据类型、变量声明、全局变量和I/O映射。特别提到全局变量如何映射写入,以及结构变量的应用。 3. 引用[3]介绍了CODESYS的ST语言中的关键字及变量类型。 4. 引用[4]展示了C++中结构体成员变量引用(通过指针),但注意这不是CODESYS,不过结构体在CODESYS中也有类似概念(STRUCT)。 5. 引用[5]讨论了引用和指针的区别,但这是C++的内容,在CODESYS中我们主要使用变量引用而不是指针(因为CODESYS的ST语言不直接支持指针)。 在CODESYS中,变量引用主要涉及以下几个方面: ### 1. 变量的声明与作用域 - **局部变量**:在程序、函数块或方法内部声明,只在声明它的块内有效。 - **全局变量**:在全局变量列表中声明,可以被整个项目中的程序访问。引用[2]详细说明了全局变量的声明和映射。 ### 2. 结构体(STRUCT)变量引用 CODESYS支持结构体,引用结构体成员使用点操作符。例如: ```pascal // 定义结构体 TYPE MotorParameter : STRUCT Velocity : REAL; Acceleration : REAL; END_STRUCT END_TYPE // 声明结构体变量 VAR motor1: MotorParameter; END_VAR // 引用成员 motor1.Velocity := 100.0; ``` ### 3. 数组和结构体数组 引用[4]虽然展示的是C++,但在CODESYS中结构体数组的成员引用也是类似的,使用下标和点操作符。例如: ```pascal VAR students: ARRAY[1..3] OF Student; // 假设Student是一个结构体类型 END_VAR // 给第一个学生的年龄赋值 students[1].age := 20; ``` ### 4. 引用(REFERENCE)类型 在CODESYS中,可以使用引用(REFERENCE)来创建变量的别名。引用类型通过`REF_TO`关键字声明。例如: ```pascal VAR originalValue: INT := 100; refValue: REF_TO INT; END_VAR refValue REF= originalValue; // 建立引用关系 refValue^ := 200; // 通过引用修改变量,originalValue也变为200 ``` 注意:使用引用时,通过`^`操作符来访问被引用变量。 ### 5. 面向对象编程中的属性引用 引用[1]提到在面向对象编程中,访问对象的属性无需完整路径(在同一个对象内部)。例如,在一个函数块(FB)内部,可以直接访问自己的属性(成员变量): ```pascal FUNCTION_BLOCK MyFB VAR count: INT; END_VAR METHOD Increment : INT // 在方法内部直接访问count count := count + 1; Increment := count; ``` ### 6. I/O映射 引用[2]提到I/O映射,这是将变量与硬件I/O点关联的过程。在CODESYS中,可以通过设备树中的I/O映射表或者直接在变量声明时使用`AT`关键字。例如: ```pascal VAR input1 AT %IX0.0: BOOL; // 映射到输入位0.0 END_VAR ``` ### 总结CODESYS变量引用的规则: 1. **普通变量**:直接使用变量名。 2. **结构体成员**:使用点操作符(`.`)。 3. **数组元素**:使用方括号(`[]`)和下标。 4. **引用类型**:使用`REF_TO`声明,用`REF=`建立引用关系,用`^`访问被引用变量。 5. **I/O映射变量**:使用`AT`关键字指定物理地址。 注意:在CODESYS中,没有指针操作(除了引用类型),所以不会像C++那样使用`->`操作符。 §§相关问题§§ 1. CODESYS中引用类型(REF_TO)和指针有什么区别? 2. 如何在CODESYS中实现结构体数组的遍历? 3. CODESYS中全局变量如何声明和引用? 4. CODESYS的I/O映射具体如何配置? </think>### CODESYS变量引用的方法与规则 在CODESYS中,变量引用主要通过**直接访问**、**结构体成员访问**和**引用类型(REF_TO)** 三种方式实现,具体规则如下: #### 一、直接变量引用 1. **全局变量** 在全局变量列表中声明的变量可被所有程序直接访问,无需路径前缀: ```pascal VAR_GLOBAL g_nCounter : INT; // 全局变量声明 END_VAR ``` 其他程序直接调用:`g_nCounter := g_nCounter + 1;` 2. **局部变量** 在函数块(FB)或程序(PRG)内部声明的变量仅在作用域内有效: ```pascal PROGRAM MAIN VAR nLocalVar : INT := 0; // 局部变量 END_VAR ``` #### 二、结构体变量引用 1. **成员访问** 使用点运算符`.`访问结构体成员: ```pascal TYPE MotorPara : STRUCT fVelocity : REAL; nPosition : DINT; END_STRUCT END_TYPE VAR stMotor : MotorPara; END_VAR ``` 赋值:`stMotor.fVelocity := 10.5;` 2. **结构体数组访问** 通过索引访问结构体数组成员: ```pascal VAR arrMotors : ARRAY[1..3] OF MotorPara; END_VAR ``` 引用:`arrMotors[2].nPosition := 1000;` #### 三、引用类型(REF_TO) 1. **引用声明与绑定** 使用`REF_TO`声明引用变量,通过`REF=`绑定目标: ```pascal VAR nOriginal : INT := 5; refValue : REF_TO INT; END_VAR refValue REF= nOriginal; // 绑定引用 refValue^ := 10; // 修改原值(nOriginal变为10) ``` 2. **引用特性** - 不占用额外内存空间(仅存储地址) - 修改引用值即修改原变量值 - 引用未绑定时值为`0`或`NULL` #### 四、特殊规则 1. **I/O映射变量** 使用`AT`关键字直接映射硬件地址: ```pascal VAR bInput AT %IX0.0 : BOOL; // 映射输入位0.0 END_VAR ``` 2. **命名空间访问** 跨库访问需添加库名前缀: ```pascal LibraryA.fbMotor.Start(); // 访问其他库的函数块 ``` 3. **只读属性访问** 通过`GET`方法访问只读属性: ```pascal nCurrentSpeed := fbMotor.GetSpeed(); ``` > **关键区别**:CODESYS的`REF_TO`与指针不同,引用必须初始化绑定且不可执行地址运算[^5],而指针允许空值和地址操作(如引用[4]的C++指针示例)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值