【C++进阶之路】初始C++语法(下)

news2024/11/17 10:51:24

文章目录

  • 一.引用
    • 1.基本概念
    • 2.使用场景
      • 函数参数
      • 函数返回值
    • 3.优点
    • 4.指针与引用的区别
  • 二.内联函数
    • 引入
    • 1.默认设置
    • 2.建议
    • 3.声明与定义(不同文件)
    • add.cpp
    • add.h
    • test.cpp
  • 三.auto
    • 1.必须有初始值
    • 2.只能确定一个类型
    • 3.auto可以为类型的一部分
    • 4.函数参数和自定义类型不可识别
    • 5.auto可对类型取别名,但&不可省
    • 6.语法糖——for+auto
    • 打印数组
    • 修改数组
    • 数组传参传的是数组首元素的地址
  • 四.空指针

一.引用

  • 指针是如何访问或者修改变量的?
#include<stdio.h>
int main()
{
	int a = 0;
	int* pa = &a;
	int** ppa = &pa;
	**ppa = 1;
	printf("%d\n", a);
	return 0;
}

这里的ppa是二级指针,通过解引用访问一级指针,再对一级指针解引用访问变量a的空间,将其赋值为1.
图解:
在这里插入图片描述

  • 指针是如何访问或者修改变量的?

我们使用多级指针访问变量是否麻烦呢
答: 可能是在某些特定的场景下麻烦,因此出了引用。

1.基本概念

  • 引用不是新定义一个变量,而是给已存在变量取了一个别名编译器不会为引用变量开辟内存空间它和它引用的变量共用同一块内存空间
  • 例如: 你的本名是你,你的外号也是你,或者水浒传的李逵,外号是“铁牛” 和“黑旋风”,但都是李逵

代码:

#include<iostream>
using std::cout;
using std::endl;
int main()
{
	int a = 0;
	int& b = a;//为了不增加符号负担,选取&作为取别名
	b = 1;
	cout << a << endl;
	return 0;
}

图解:a与b公用一块空间
在这里插入图片描述
注意细节:

  1. 取别名语法规定必须设置初始值

错误示例:

#include<iostream>
using std::cout;
using std::endl;
int main()
{
	int a = 0;
	int& b;
	return 0;
}

2.别名与原变量名共用一块空间

证明:

#include<iostream>
using std::cout;
using std::endl;
int main()
{
	int a = 0;
	int& b =a;
	cout << &a << endl;
	cout << &b << endl;
	return 0;
}
  1. 别名一经设置不能被修改!

注意代码解读:

int main()
{
	int a = 0;
	int& b = a;
	int x = 2;
	b = x;//这里是将x的值赋值给a变量,而不是给x取别名为b!
	return 0;
}
  1. 一个变量可以有多个别名,对别名也可以取别名

举例:

int main()
{
	int a = 0;
	int& b = a;
	int& c = a;
	int& d = b;//对别名取别名还是a变量
	return 0;
}

关于单链表中引用的使用:

typedef struct SListNode
{
	int val;
	int* next;
}SListNode,*PNode;
//这里的PNode即为SListNode*
void SListPushBack(PNode& p, int x)//相当于对一级结构体指针取别名
{
	//……功能省略
}
int main()
{
	SListNode* head;
	SListPushBack(head, 1);
	return 0;
}

2.使用场景

函数参数

#include<iostream>
using std::cout;
using std::endl;
void Swap(int& n1, int& n2)//传进去相当于对原变量取别名
{
	int tmp = n1;
	n1 = n2;
	n2 = tmp;
}
int main()
{
	int x = 2;
	int y = 1;
	cout << "before " << x <<" "<< y << endl;
	Swap(x, y);
	cout << "after " << x <<" "<< y << endl;
	return 0;
}
  • 这里的交换两个值实际上就是通过对原变量取别名从而将原变量的值进行交换,不过省去了指针的使用,这样很方便。

函数返回值

  • 先引出我们的整形变量作为返回值
int add()
{
	int n = 0;
	 n++;
	return n;
}
int main()
{
	int ret = add();

	return 0;
}
  • 在栈帧返回时,将n的临时拷贝放在eax寄存器中返回,eax寄存器并不会随着栈帧的摧毁而销毁,因此再将eax的值赋值给ret,完成赋值。
  • 因此:这里的返回值其实是n的一份临时拷贝。
int& add()
{
	int n = 0;
	 n++;
	return n;
}
int main()
{
	int ret = add();//这里的add()可看做n变量的别名

	return 0;
}
  • 这里调用函数的返回的结果是n的别名,通过别名访问n的值,但是在返回的途中栈帧已经被销毁,使用权已经返还给操作系统,因此这里访问其实是很危险的,这跟野指针是一样的道理,我们无法确定访问到是否是我们想要的值,如果侥幸访问拿到的是我们想要的值,但如果我们在此代码的基础上稍加修改。
  • 因此:这里返回的是n的别名。
#include<iostream>
using std::cout;
using std::endl;
int& add()
{
	int n = 0;
	 n++;
	return n;
}
int main()
{
	int& ret = add();
	//add()=1;
	cout << ret << endl;
	printf("hello\n");
	cout << ret << endl;
	return 0;
}
  • 原来的栈帧被printf调用,破坏了原来的未被修改的栈帧,因此这里打印的值是不确定的!
  • 因此:使用取别名当返回值时,使用应不是栈上开辟的变量。
  • 此外:返回值作为别名可以直接进行修改!
  1. const的使用
  • const修饰的变量表示只读状态不可被修改

可这样对一个常量能取别名吗?

int main()
{
	int& b = 1;
	return 0;
}
  • 这样表示其实是对1取别名,并且其值可被修改,因此语法错误。

如何正确的对一个常量取别名?

int main()
{
	const int& b = 1;
	return 0;
}
  • 这样表示其为只读状态,因此不可被直接修改,因此表示正确。

应用于变量中
码1:

int main()
{
	int a = 0;
	const int& b = a;
	a++;
	//b++;
	return 0;
}

  • 这样指的是对a变量的取一个别名,这个别名只可读不可访问,就像VIP与普通用户的区别,而a变量可访问也可修改。
  • 因此:对变量取别名,使用权限是可以缩小的。

码2:
这样可以吗?

int main()
{
	const int a = 0;
	int& b = a;
	return 0;
}
  • 显然跟常量是一样的,a是只读状态,因此对a取别名也应该是只读状态,所以b的前面应该加上const进行修饰
  • 因此:访问权限不能扩大

码3:

int main()
{

	int a = 0;
	float b1 = 11.0f;
	a = b1;//这里的b1其实是隐式类型转换的结果,将b1值转换成浮点数,这里的b1是浮点数的常量
	int& a1 = a;
	const float& b = a;
	//同理这里的a也是隐式类型转换的结果,既然是结果那就是float类型的常量,常量就是只读状态
	//因此是要加const 并且是float类型的常量
	printf("%d %f", a, b);
	return 0;
}
  • 因此:变量是不能起不同类型的别名的,我们看到的其实是隐式类型转换后的不同类型的常量.
  • 总结:访问权限不能扩大,只能平移或者缩小。

3.优点

  • 作为函数参数,实参过大时,取别名会降低传参的成本,因而提升效率。
  • 作为返回值,可以当做别名直接进行修改,返回值过大也可降低拷贝提升效率。

4.指针与引用的区别

int main()
{
	int a = 0;
	int* pa = &a;
	int& b = a;
	return 0;
}

反汇编代码:
在这里插入图片描述

  • 说明:lea是取地址的意思
  • 第一句:将0赋值给a地址处向上的4个字节
  • 第二句:对a取地址将其放在eax寄存器中
  • 第三句:将eax的内容放在pa地址处向上的4个字节
  • 第四句:对a取地址将其放在eax寄存器中
  • 第五句:将eax的内容放在b地址处向上的4个字节

  • 因此我们可以得到在反汇编的角度(底层原理)指针和引用是没有区别的,同样是要开辟空间的。
  • 那为什么我们要说引用不等于指针呢?
  • 在语法层面上, 我们经过实验可知(上文),引用也就是取别名的地址是跟原变量的地址保持一致的,而C语言则是跟底层原理保持一致的
  • 因此:C++将底层的一些东西 进行封装,在语法上呈现给我们的是上层的东西,可知上层跟下层还是有些许不同的。

二.内联函数

引入

#include<iostream>
using std::cout;
using std::endl;
int add(int x,int y)
{
	return x + y;
}
int main()
{

	for (int i = 0; i < 1000; i++)
	{
		cout << add(1, i) << endl;
	}
	return 0;
}
  • 如何优化这一段代码?这段代码为什么需要优化?

  • 学过C语言的你想必会使用宏函数进行优化,那为什么要这样优化呢?学过函数栈帧其实就很简单,函数调用是需要调用函数栈帧的,当栈帧的空间大于我们有效代码的空间时,使用函数的负担就会较大

  • 如何进行优化?

#include<iostream>
using std::cout;
using std::endl;
#define ADD(x,y) (((x)+(y))*10)//ADD建议全大写这可是程序员之间的悄悄约定过的哦
int main()
{

	for (int i = 0; i < 1000; i++)
	{
		cout << ADD(1, i) << endl;
	}
	return 0;
}
  • 那这样优化有什么好处和坏处呢?
  • 好处:直接进行替换,减小了栈帧的消耗,并且不要求类型,提升了运行的速度。
  • 坏处:如果对宏不熟练,写这个宏极易容易出错,这里的括号是不能省的,仔细想想为什么?不便于调试。副作用极大。

为了解决C语言的缺陷,所以设计者在C语言的基础上设计出了内联函数
用法:只需在函数的返回值类型前+inline即可,本质上是有效指令的替换.

  • 有这么简单么?当然没有

1.默认设置

#include<iostream>
using std::cout;
using std::endl;
inline int add(int x,int y)//这里加了inline
{
	return x + y;
}
int main()
{

	for (int i = 0; i < 1000; i++)
	{
		cout << add(1, i) << endl;
	}
	return 0;
}

汇编指令:
在这里插入图片描述

  • 结果:我们在调试阶段去调用了add函数,而没有把函数的指令放在这里,我们写错了吗?

  • 当然没有,这是在VS2019的默认值,在调试不会将指令进行替换。

  • 怎么设置?
    第一步:
    在这里插入图片描述
    第二步:

在这里插入图片描述
第三步:
在这里插入图片描述
看设置之后的反汇编代码:
在这里插入图片描述

  • add函数的指令变成了这样就是add函数的功能。

2.建议

  • 试想:我们如果写一个函数具有一百行代码,调用一千次,如果使用内联会产生怎么样的结果?或者说产生多少条指令?
  • 答案:100*1000=10W行指令,代码是不是爆炸了?
  • 因此:编译器会把决定权交给你么?当然不会。
  • 因此:我们写内联函数只是起建议的作用。

如何证明:

#include<iostream>
using std::cout;
using std::endl;
#define ADD(x,y) (((x)+(y))*10)
inline int add(int x,int y)
{
	cout << "hello" << endl;
	cout << "hello" << endl;
	cout << "hello" << endl;
	cout << "hello" << endl;
	cout << "hello" << endl;
	cout << "hello" << endl;
	cout << "hello" << endl;
	cout << "hello" << endl;
	cout << "hello" << endl;
	cout << "hello" << endl;
	cout << "hello" << endl;
	cout << "hello" << endl;
	return x + y;
}
int main()
{

	for (int i = 0; i < 1000; i++)
	{
		cout << add(1, i) << endl;
	}
	return 0;
}

再次查看反汇编代码:
在这里插入图片描述

  • 此时又变成了函数的调用。

联系:register 也不会把是否放在寄存器的决定权交给你,只是起建议的作用。

3.声明与定义(不同文件)

add.cpp

inline int add(int x, int y)
{
	return x + y;
}

add.h

inline int add(int x, int y);

test.cpp

#include<iostream>
#include"add.h"
using std::cout;
using std::endl;
int main()
{
	for (int i = 0; i < 1000; i++)
	{
		cout << add(1, i) << endl;
	}
	return 0;
}
  • ctrl+F7编译一下
    在这里插入图片描述
    我们发现是没有问题的。

  • 执行一下
    在这里插入图片描述
    链接错误

  • 原因:链接时做了生成段表(主要为函数和全局变量的地址)的工作,而内联函数的本质是替换(其地址是不会放在段表中的),当你在链接时进行查找时会发现在头文件中只有声明,但是定义不在头文件中,而在源文件中,这时你要去源文件中查找,但是段表里面并没有这个函数的地址,因此找不到所以会报错!

  • 因此:要么在头文件中写内联函数的定义,要么就直接写在主函数所在的源文件中,并且在不同源文件中定义相同的内联函数,是不会报错的,因为就不会在段表里出现这几个函数!

  • 拓展:本质上代码的运行都会化作二进制指令的执行,计算机将指令加载到内存中,每条指令都有一条特定的地址,常规函数的调用会指行函数调用指令,程序将在函数调用后立刻存储该指令的内存地址,并将函数的参数拷贝到堆栈,跳到目标函数的起点内存单元执行代码,然后跳回地址被保存的指令处,这来回调用会存在一定的开销

三.auto

C语言的auto的作用是修饰声明周期和作用域都是局部的的变量,但基本上没什么用,所以在C++上改进了一下——自动识别(变量的数据)然后定义其类型。

  • C++11中,标准委员会赋予了auto全新的含义即:auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

1.必须有初始值

  • 识别的依据是初始化的值,编译器是先推导初始化的值判断变量类型,然后把数据放在该判断好的类型中,因此初始化的数据是auto的前提
int main()
{
	auto x = 1;
	int y = 1;
	float z = 1.0;
	auto n = 1.0f;
	//auto w ;这句代码是不对的
	return 0;
}

2.只能确定一个类型

  • 当一行有多个数据时,如果用auto,这些数据类型必须是相同的,否则会出现无法判断的情况。
int main()
{
	int x = 0, y = 1.0f;//这里可是发生了隐式类型转换
	auto x = 0, y = 1;
  //auto x =0,y = 1.0f;这行代码会报错
	return 0;
}

3.auto可以为类型的一部分

  • 一级指针的类型可以拆分为:指向数据的类型+ *
  • 那这里指向的数据的类型就可以用auto来表示
#include<iostream>
#include"add.h"
using std::cout;
using std::endl;
int main()
{
	int a = 0;
	auto* p = &a;
	cout << typeid(p).name() << endl;//这里打印的就是int*
	cout << typeid(a).name() << endl;
	return 0;
}

4.函数参数和自定义类型不可识别

  • 函数参数如果具有自动识别,那函数的类型识别就丧失了
  • 自定义类型是无法让编译器进行推导的,因此无法识别
  • 自定义类型包括:数组,联合体,结构体。

错误示例——自定义类型:

typedef struct Student
{
	int age;
	char name[20];
	int Id;
}Student;

int main()
{
	auto x = { 18,"shunhua",11111111 };//无法识别
	return 0;
}

错误示例——函数参数

int add(int x, auto y)
{
	return x + y;
}

5.auto可对类型取别名,但&不可省

  • auto+&本质上是引用,不是类型,所以取别名时必须加&
int main()
{
	int a = 0;
	auto& x = a;
	
	return 0;
}

6.语法糖——for+auto

打印数组

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (auto x : arr)
	{
		cout << x << endl;
	}
	return 0;
}
  • 这句代码的意思为:依次取出arr数组中的元素,将其放在x的临时变量中。从起始位置读取直到数组读取结束。

修改数组

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	for (auto& x : arr)
	{
		cout << x << endl;
	}
	return 0;
}
  • 我们可以使用取别名的形式进行修改。

数组传参传的是数组首元素的地址

void Print(int arr[10])
{
	for (auto x : arr)//这里是指针不是数组因此语法报错
	{
		cout << x << endl;
	}
}
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	Print(arr);
	return 0;
}

四.空指针

#include<iostream>
using std::cout;
using std::endl;
int main()
{
	auto x = 0;
	auto y = NULL;
	auto z =(void *)NULL;
	auto n = nullptr;

	cout << typeid(x).name() << endl;
	cout << typeid(y).name() << endl;
	cout << typeid(z).name() << endl;
	cout << typeid(n).name() << endl;

	return 0;
}

运行结果:
在这里插入图片描述

  • NULL的定义

在这里插入图片描述

  • 结论:在C++下NULL是被当做整形0来看待的,并且引出了一个新的关键字nullptr,其类型为std::nullptr_t。
  • nullptr在被赋值给其它类型时,会默认转换为其他指针类型的值,但不会转换为任何整数类型!

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

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

相关文章

Ubuntu20.04部署YOLOv5

目录 前言一、环境配置1 显卡驱动安装1.1 卸载显卡驱动1.2 准备工作1.3 驱动安装1.4 验证 2 CUDA安装2.1 准备工作2.2 CUDA下载2.3 CUDA安装2.4 配置环境变量2.5 验证2.6 小结 3 cuDNN安装3.1 cuDNN下载3.2 cuDNN安装3.3 小结 4 TensorRT安装4.1 TensorRT下载4.2 TensorRT安装4…

UOS-----本地YUM源配置

1. cd /etc/apt/sources.list.d/ 将文件中的两个list配置文件内容注释掉&#xff0c;并保存 2. cd /etc/apt/ vi sources.list 将配置文件内容注释 3. cd /etc/apt/sources.list.d/ vi local.list (创建一个新的list文件&#xff0c;作为本地yum配置文件) 添…

电脑怎么压缩图片大小,4个通用方法分享

电脑怎么压缩图片大小&#xff1f;我相信这个问题很多小伙伴都遇到过的。我们压缩图片大小的主要原因是为了优化网站、应用程序或移动设备的性能。大尺寸的图片文件需要更多的存储空间和带宽&#xff0c;这将导致网页加载速度变慢&#xff0c;浪费用户时间并影响用户体验。此外…

香港科技大学有什么好的专业?

香港科技大学创办于1991年10月&#xff0c;是一所坐落于香港清水湾半岛的公立研究型大学。大学设有4个学院&#xff1a;工学院、理学院、人文社会科学学院和工商管理学院&#xff0c;还设有2个研究院&#xff1a;香港科技大学公共政策和行政研究生院和香港科技大学霍英东研究院…

nginx 配置代理ip访问https的域名配置

目录 问题背景 解决方式 正向代理&#xff1a; 反向代理&#xff1a; 通俗点儿一句话&#xff0c;正向与反向的区别&#xff1a; 问题背景 在某些单位或机构内部&#xff0c;访问互联网接口需要通过指定的服务器去访问&#xff0c;那我们就需要通过代理 ip 和 端口去访问外…

云计算基础——虚拟化

虚拟化技术简介 虚拟化是一个广义的术语&#xff0c;在计算机方面通常是指计算元件在虚拟的基础上而不是真实的基础上运行 虚拟化是一种经过验证的软件技术&#xff0c;它正迅速改变着IT的面貌&#xff0c;并从根本上改变着人们的计算方式 虚拟化是一个抽象层&#xff0c;它…

【C++学习】类和对象--运算符重载

运算符重载概念&#xff1a;对已有运算符重新定义&#xff0c;赋予其另一种功能&#xff0c;以适应不同的数据类型。 作用&#xff1a;实现两个自定义数据类型相加的运算。 目录 加号运算符重载 1.成员函数重载 2.全局函数重载 左移运算符重载<< 递增运算符重载 赋值…

java堆排序

堆排序是最基本的排序算法&#xff0c;简单来说就是把一堆数据&#xff08;数组&#xff09;分成两个相等的部分&#xff0c;其中一个部分作为数组的开头&#xff0c;另一个部分作为数组的结尾。之后在对这两个相等的部分进行比较&#xff0c;如果在比较之后发现这个数组中有一…

读懂什么是RDMA

一.什么是RDMA 1.RDMA主要体现 2.如何理解RDMA和TCP技术的区别&#xff1f; 3.使用RDMA的好处包括&#xff1a; 二.什么是RoCE&#xff1f; 1. RDMA协议包含: Infiniband&#xff08;IB&#xff09; 2. 为什么RoCE是目前主流的RDMA协议&#xff1f; …

GhostNet

文章目录 相关文章一、轻量化网络结构1. 分组卷积2. 深度可分离卷积 二、GhostNet1. 动机2. Ghost Module 相关文章 https://blog.csdn.net/search_129_hr/article/details/130280697 https://blog.csdn.net/c2250645962/article/details/104601305 一、轻量化网络结构 目的…

信息收集(一)域名信息收集

前言 信息收集也叫做资产收集。信息收集是渗透测试的前期主要工作&#xff0c;是非常重要的环节&#xff0c;收集足够多的信息才能方便接下来的测试&#xff0c;信息收集主要是收集网站的域名信息、子域名信息、目标网站信息、目标网站真实IP、敏感/目录文件、开放端口和中间件…

052:cesium加载网格地图

第052个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中加载grid地图。一个 ImageryProvider,它在每个具有可控背景和发光的图块上绘制线框网格。 可能对自定义渲染效果或调试地形很有用。 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 …

redis 教程 6(Redis 的Pipeline , Lua)

Redis 的Pipeline, Lua PipelinePipeline简介为什么需要PipelinePipeline 性能测试与原生批量命令对比 LuaLua 与事物Lua 的用法Redis 如何管理Lua脚本 Pipeline Pipeline简介 Pipeline&#xff08;流水线&#xff09; 能够将一组redis命令进行组装&#xff0c; 通过一次RTT&…

fmriprep2

一. sub-subXXX文件夹 sub-subXXX.html 二. sub-subXXX文件夹 sub-sub097 / anat / figures / func / log / anat / anat文件夹内文件比较多&#xff0c;文件命名规则遵守BIDS要求( https://bids-specification.readthedocs.io/en/stable/05-derivatives/01-introduction.ht…

【国内chatgpt使用方法合集】

写在前面 Hello大家好&#xff0c; 我是【麟-小白】&#xff0c;一位软件工程专业的学生&#xff0c;喜好计算机知识。希望大家能够一起学习进步呀&#xff01;本人是一名在读大学生&#xff0c;专业水平有限&#xff0c;如发现错误或不足之处&#xff0c;请多多指正&#xff0…

2023_4_23_VS下Release怎么打断点进行debug

&#x1f37f;*★,*:.☆(&#xffe3;▽&#xffe3;)/$:*.★* &#x1f37f; &#x1f4a5;&#x1f4a5;&#x1f4a5;欢迎来到&#x1f91e;汤姆&#x1f91e;的csdn博文&#x1f4a5;&#x1f4a5;&#x1f4a5; &#x1f49f;&#x1f49f;喜欢的朋友可以关注一下&#xf…

MySQL——流程控制函数

在 MySQL 中&#xff0c;流程控制函数是指可以控制存储过程&#xff08;stored procedure&#xff09;或函数&#xff08;function&#xff09;中执行流程的语句。以下是几个常用的流程控制函数&#xff1a; 1. IF函数 实现IF……ELSE……的效果。 # 如果expr1为true&#x…

深入探究java中的 xxxable和xxxator

前言 相信有一定工作经验的朋友,都见过或者用过xxxable和xxxator ,比如常见的Comparable和Comparator, 还有还有常见并且容易迷糊的Iterable和Iterator, 看这名字,前两个是和比较相关的, 后两个是和迭代相关. 但是命名如此相似的接口, 又有何区别呢?各自的用途又是什么呢? 今…

详解车载设备FOTA测试

作者 | 李伟 上海控安安全测评部总监 来源 | 鉴源实验室 引言&#xff1a;上一篇文章我们以车载Tbox为例介绍了相关的性能测试&#xff08;车载TBOX嵌入式设备软件的性能测试&#xff09;&#xff0c;本篇我们介绍另外一个重要功能的专项测试&#xff1a;OTA&#xff08;Over…

MySQL安装及卸载

安装 mysql现在安装的是5.7.mysql的安装方式有两种: 一种是exe方式 另外一种解压版 这次就使用解压版安装 解压缩到非中文目录 编写配置文件 1) 在安装目录下新建my.ini的配置文件 打开文件后缀和隐藏文件显示 2) 新建文件内编写内容 [Client] port 3306 [mysqld] #设置330…