单片机 struct的外部引用_C++增强与引用

c++语法检查增强

305ca5d578f2cfd7be9bbb4872a69253.png

c5cf3728422528ce1acca2a53b4fdb4f.png

以上c代码c编译器编译可通过,c++编译器无法编译通过

84aa892e87b9bb056b39781c5aaad572.png

c++对结构体的增强

1、c中定义结构体变量需要加上struct关键字,c++不需要

2、c中的结构体只能定义成员变量,不能定义成员函数。c++即可以定义成员变量,也可以定义成员函数

C语言:

struct stu
{
    int num;
    char name[32];
/* c语言 不允许在结构体中  定义成员函数
 void func(void)
 {
 printf("我是结构体中的func");
 }
 */
};
void test01()
{
 //C语言必须加struct
    struct stu lucy = {100, "lucy"};
}

c++:

struct stu
{
    int num;
    char name[32];


 //c++语言 允许在结构体中  定义成员函数
 void func(void)
 {
 printf("我是结构体中的func");
 }


};
void test01()
{
 //C++语言不用加struct
    stu lucy = {100, "lucy"};
 
 //调用结构体中的成员方法(成员函数)
    lucy.func();
}

c++新增bool类型

f3e3a6478da7fbc2c071ac7b5e42a90c.png
void test02()
{
    bool mybool;
    cout<<"sizeof(bool) = "<<sizeof(bool)<<endl;//1字节
    mybool = false;
    cout<<"false = "<<false<<endl;//0
    cout<<"true = "<<true<<endl;//1
}

三目运算符功能增强 a>b?a:b

1、c语言三目运算表达式返回值为数据值,为右值,不能赋值

void test02()
{
    int a = 10;
    int b = 20;
 printf("C语言:%dn", a>b?a:b);//20


 //a>b?a:b整体结果 右值(不能被赋值)
    a>b?a:b = 100;//err不能被赋值
}

2、c++语言三目运算表达式返回值为变量本身(引用),为左值,可以赋值

void test02()
{
    int a = 10;
    int b = 20;
    cout<<"c++中:"<<(a>b?a:b)<<endl;


 //a>b?a:b整体结果是变量本身(引用) 左值(能被赋值)
    a>b?a:b = 100;//b =100
}

能被赋值的就是左值 不能被赋值的就是右值

c++中const

1、c语言中

const int a = 10;//不要把a看成常量
//a的本质 是变量 只是 只读变量

a、c语言的const修饰全局变量 默认是(外部链接的)

fun.c

//c语言的const修饰全局变量 默认是(外部链接的)
//外部链接:其他源文件 可以使用
const int num = 100;//只读的全局变量 内存放在文字常量区(内存空间只读)

main.c

//对fun.c中的num进行声明(不要赋值)
extern const int num;


void test03()
{
 printf("num = %dn",num);
 //num = 200;//err num只读


 //C语言中const 修饰变量名 说明变量名为只读(用户不能通过变量名data进行赋值)
 const int data = 100;//局部只读变量 内存在栈区(内存可读可写)
 //data = 200;//err


 printf("data = %dn",data);
 //但是:如果知道data的地址 可以通过地址间接的修改data所对应空间的内容
    int *p = (int *)&data;
 *p = 2000;
 printf("data = %dn",data);//ok 200
}

总结:在c语言中

1、const修饰全局变量num 变量名只读 内存空间在文字常量区(只读)、不能通过num的地址 修改空间内容

2、const修饰局部变量data 变量名只读 内存空间栈区(可读可写),可以通过data地址 间接的修改空间内容

2、c++中的const 深入理解

fun.cpp

//const修饰的全局变量 默认是内部链接(只在当前源文件有效 不能直接用于其他源文件)
//const int num = 100;
//如果必须用在其他源文件 使用只读的全局变量 必须加extern将num转换成外部链接
extern const int num = 100;

main.cpp

//声明
extern const int num;
struct Person
{
    int num;
    char name[32];
};
void test04()
{
    cout<<"全局num = "<<num<<endl;//err 不识别num


 //1、c++中 对于基础类型 系统不会给data开辟空间 data放到符号表中
 const int data = 10;
 //data = 100;//err 只读
    cout<<"data = "<<data<<endl;
 //2、c++中当 对data 取地址的时候 系统就会给data开辟空间
    int *p = (int *)&data;
 *p = 2000;
    cout<<"*p = "<<*p<<endl;//空间内容修改成功 2000


    cout<<"data = "<<data<<endl;//data 还是10为啥?


 //2、当以变量的形式 初始化 const修饰的变量 系统会为其开辟空间
    int b = 200;
 const int a= b;//系统直接为a开辟空间 而不会把a放入符号表中
    p = (int *)&a;
 *p = 3000;
    cout<<"*p = "<<*p <<endl;//3000
    cout<<"a = "<<a <<endl;//3000


 //3、const 自定义数据类型(结构体、对象) 系统会分配空间
 const Person per = {100,"lucy"};
 //per.num = 1000;//err
    cout<<"num = "<<per.num<<", name = "<<per.name<<endl;//100 lucy
    Person *p1 = (Person *)&per;
    p1->num = 2000;
    cout<<"num = "<<per.num<<", name = "<<per.name<<endl;//2000 lucy
}

总结:c++总结

1、const int data = 10;//data先放入符号表

2、如果对data取地址 系统才会给data开辟空间

3、const int a = b;//b是变量名 系统直接给a开辟空间 而不放入符号表

4、cosnt 修饰自定义数据 系统为自定义数据开辟空间

尽量const替换#define

769cd39bd54682cdce5e770c9ecdae92.png

1、宏没有类型 const有

#define MAX 1024
const short my_max =1024;
void func(short i)
{
    cout<<"short函数"<<endl;
}
void func(int i)
{
    cout<<"int函数"<<endl;
}
void test05()
{
 func(MAX);//int 函数


 func(my_max);//short函数
}

2、宏的作用域是整个文件 const的作用域 以定义情况决定

void my_func(void)
{
 //作用范围 是当前复合语句
 const int my_num = 10;


 //作用范围 当前位置 到文件结束
    #define MY_NUM 10
}
void test06()
{
 //cout<<"my_num = "<<my_num<<endl;//err 不识别
    cout<<"MY_NUM = "<<MY_NUM<<endl;//ok 能识别
}

3、宏不能作为命名空间的成员 const可以

namespace A {
 // const可以作为成员
 const int my_a=100;


 //MY_A 属于文件 不属于A
    #define MY_A 200
}
void test07()
{
    cout<<"my_a = "<<A::my_a<<endl;
 //cout<<"MY_A = "<<A::MY_A<<endl;//err
    cout<<"MY_A = "<<MY_A<<endl;
}

引用(重要)给已有变量取个别名

语法:

1、&和别名 结合 表示引用

2、给某个变量取别名 就定义某个变量

3、从上往下替换

int num = 10;
int &a = num;//此处 &不是取地址 而是标明 a是引用变量(a 是 num的别名)

注意:

1、引用必须初始化

2、引用一旦初始化 就不能再次修改别名

int num = 10;
int &a = num;


int data = 20;
a = data;//不是data别名为a  而是将data值赋值a(num)

练习

int num = 10;
int &a = num;//a就是num的别名  a==num


cout<<"num = "<<num<<endl;//10
//对a赋值 == 对num赋值
a=100;
cout<<"num = "<<num<<endl;//100


//a是num的别名 所以num和a具有相同的地址空间
cout<<"a 的地址:"<<&a<<endl;
cout<<"num 的地址:"<<&num<<endl;

引用 给数组 取个别名

1、方式一:

void test02()
{
    int arr[5] = {10,20,30,40,50};
 //需求:给arr起个别名
 int (&my_arr)[5] = arr;//my_arr就是数组arr的别名


    int i=0;
 for(i=0;i<5;i++)
 {
        cout<<my_arr[i]<<" ";
 }
    cout<<endl;
}

2、法法二:配合typedef

void test03()
{
    int arr[5] = {10,20,30,40,50};
 //1、用typedef 给数组类型 取个别名
 //TYPE_ARR就是一个数组类型(有5个元素 每个元素位int)
    typedef int TYPE_ARR[5];


 //myArr就是数组arr的别名
 TYPE_ARR &myArr=arr;


    int i=0;
 for(i=0;i<5;i++)
 {
        cout<<myArr[i]<<" ";
 }
    cout<<endl;
}

引用作为函数的参数

void my_swap1(int a,int b)
{
    int tmp = a;
    a = b;
    b=tmp;
}
void my_swap2(int *a,int *b)//a=&data1,b =data2;
{
    int tmp = *a;
 *a = *b;
 *b = tmp;
}


void my_swap3(int &a, int &b)//a=data1,b=data2
{
    int tmp = a;
    a = b;
    b= tmp;
}
void test04()
{
    int data1 = 10,data2=20;
    cout<<"data1 = "<<data1<<", data2 = "<<data2<<endl;
 //my_swap1(data1,data2);//交换失败
 //my_swap2(&data1,&data2);//交换成功
 my_swap3(data1,data2);//交换成功(推荐)
    cout<<"data1 = "<<data1<<", data2 = "<<data2<<endl;
}

引用作为函数的返回值

给函数的返回值 取个别名

//引用作为函数的返回值类型
int& my_data(void)
{
    int num = 100;
 return num;//err 函数返回啥变量 引用就是该变量的别名
 //函数的返回值是引用时  不要返回局部变量
}


int& my_data1(void)
{
 static int num = 200;
 return num;//ok
}
void test05()
{
 //ret是别名 ret是num的别名
    int &ret = my_data();
 //cout<<"ret = "<<ret<<endl;//非法访问内存


    int &ret1 = my_data1();//ret1是num的别名
    cout<<"ret = "<<ret1<<endl;
}

当函数返回值作为左值 那么函数的返回值类型必须是引用。

引用的本质 (了解)

引用的本质在c++内部实现是一个指针常量. Type& ref = val; // Type* const ref = &val;

c++编译器在编译过程中使用常指针作为引用的内部实现,因此引用所占用的空间大小与指针相同,只是这个过程是编译器内部实现,用户不可见

int data = 10;
int &a = data;//a就是data的别名
//编译器内存转换:int * const a = &data;


a=100;//等价于data=100
//*a = 100;//*a == data

指针的引用(了解)

#include<stdlib.h>
#include<string.h>
void my_str1(char **p_str)//p_str = &str
{
 //*p_str == *&str == str
 *p_str = (char *)calloc(1,32);
 strcpy(*p_str, "hello world");


 return;
}
void my_str2(char* &my_str)//char* &my_str = str;my_str等价str
{
    my_str = (char *)calloc(1,32);
 strcpy(my_str, "hello world");
 return;
}
void test07()
{
    char *str = NULL;
 //需求:封装一个函数 从堆区 给str申请一个空间 并赋值为"hello world"
 //my_str1(&str);
 my_str2(str);
    cout<<"str = "<<str<<endl;
 free(str);
}

常引用

1、引导出常引用(重要)

typedef struct
{
    int num;
    char name[32];
}STU;
void myPrintSTU1(STU tmp)//普通结构体变量作为形参 开销太大
{
    cout<<sizeof(tmp)<<endl;
    cout<<"学号:"<<tmp.num<<", 姓名:"<<tmp.name<<endl;
}
void myPrintSTU2(const STU &tmp)//STU &tmp=lucy;tmp是lucy的别名 tmp没有开辟独立空间
{
 //tmp.num = 2000;//err 因为tmp为常引用
    cout<<"学号:"<<tmp.num<<", 姓名:"<<tmp.name<<endl;
}
void test08()
{
 STU lucy = {100,"lucy"};


 //需求:定义一个函数 遍历lucy成员(读操作)
 myPrintSTU2(lucy);
}

2、常量的引用(了解)

void test09()
{
 //给常量10取个别名 叫num
 //int &针对的是int ,10是const int类型
 //const int 针对的是const int, 10是const int类型
 const int &num = 10;


    cout<<"num = "<<num<<endl;//10
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
07-22

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值