c++/C 的 const

本文详细介绍了C与C++中const关键字的使用方法及其差异。包括const修饰不同类型变量的特点,函数参数与返回值中const的应用,以及在类成员函数和数据成员中的使用技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

constCC++的异同

1C中,const是只量,不是常量;C++中它是常量。区用例子描述如下:

const int MAX = 10;

char buffer[MAX]; //C中它是不合法的,可以用enum define替代;C++中它是合法的。

2Cconst量分配在全局静态区;C++在常量区,编译过程中就定了。

3C++编译器并不为const量创建存储空间,而是保存在符号表里。如果用extern介入外部接或者取const量的地址,编译器必须要分配空间。

 

一、const修饰一般常量

1、常量

1)修饰一般常量简单类型的常量const修饰的常量必须初始化

      const可在明符前,也可在明符后。const常量有数据类型,而宏常量没有数据类型。编译器可以对const常量进行类型安全检查,而对宏常量只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误。     

       int constx=2;  或  const intx=2;         //等效的

const int i = 10;

const int j = i+20; //常量折叠,即编译期间将i代入

int* p = &i; //取址导致内存分配

char buffer[i]; //尽管内存分配,i还是进入了符号表

2)修饰常数组

     明一个常数可采用如下格式:

       int const a[5]={1, 2, 3, 4, 5};   const int a[5]={1, 2, 3, 4,5};          //等效的

       charbuffer[intArray[1]]; //编译错误由于数组过于复杂,编译器不把它放入符号表,而是分配内存区保存。编译期间不会知道具体值。

3)修饰常对象

      常象是指象常量,定格式如下:

       class A;

       const A a;

       A consta;            //等效的

     ,同行初始化,并且该对象不能再被更新,修const可以放在名后面,也可以放在名前面

4)修饰常指针

const int* a = & [1] 

int const *a = & [2] 

int* const a = & [3] 

const int* const a = & [4] 

         如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量

5)修饰常引用

      使用const符也可以明引用,被明的引用常引用,引用所引用的象不能被更新。

        格式如下:

     const double & v;

6const 字符串

char* p = hello;

          这时,”hello”是常量,p指针是一个指向常量的指针: constchar* p = “hello”。 如果,p[0] = a’;则程序运行崩溃,因为试图去更改常量区,行为是未定义的。

如果想要改变一个数组,需要这样定义:

   char p[] = “hello”;

注意 char [] p = “hello”是错误的!“hello”将保存在全局静态区,而不是常量区,p指向首地址。

 

2 const在函数声明中的应用                                                           

1修饰函数的常参数、该参数(变量)在函数体中无法改

     const函数的传递参数,告诉编译该变量在函数体中的无法改(不能对传递进来的指针/引用对象进行改变),从而防止了使用者的一些无意的或错误的修改。

格式如下:

void Func( const int i )

{

    i = 10;  //目的就是防止在程序里改变临时变量 i,对于用户而言是没//有影响的

}

按值传递的const可以这样写,这样用户接口更简单。

void Func( int i )

{

const int& j = i; 

}

1const常用于参数为指针或引用且只能修饰输入参数

2)若输入参数“值传递”由于函数将自动产生临时变量用于复制该参数,该参数本就不需要保护,所以不用const修饰。 

3)对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const引用传递”,目的是为了提高效率。

          void Func(A a)    改为   voidFunc(const A &a) 

4)对于内部数据类型的输入参数,不要将“值传递”的方式改为“const引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。

        void Func(int x)不应该改为void Func(const int &x)

2修饰函数的返回值

  const修饰符也可以修饰函数的返回值,是返回值不可被改变,格式如下:

       const int Fun1(); 

1)调用需注意只能用常量调用:const int N=Fun1();

2)一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载

3)如果返回const指针 则指针内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针

4)值传递,函数会把返回值赋给外部临时变量,用const无意义!不管是内部还是非内部数据类型

5)通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况

class A

{

    public:

void modify(){ a = 10; };

 

    private:

int a;

};

                              

            A Func1() { return A(); }

            Func1() = A(); //合法,产生一个临时的非const A对象

            Func1().modify(); //合法,非const A对象  可以更改数据

 

            constA Func2() { return A(); }

            Func2() = A(); //不合法

            Func2().modify(); 不合法

 

            voidFunc3( A& a) {}

             Func3( Func2() ); //不合法,因为不能 从const变成一个非const的引用

 

二、const在类中的应用 

1修饰类的成员函数

1 修饰类的成员函数时不能用于构造函数和析构函数

     const饰类的成函数 一般放在函数体后。该成员函数不能修改类中的成员变量也不能调用其他非const成员函数

     class ClassName 

    {

          public:

            int Fun() const{};//在函数内部不能改变变量值

     }

      任何不会修改数据成员的函数都应该声明为const类型。如果不慎修改了数据成员,或调用了其他非const成员函数,编译器将报错,大大提高了程序的健壮性。

2const函数成员与mutable

        如果在const函数里想改变某个变量,可将变量声明为mutable。用来替换强制转换将法(将const指针转成非const指针,然后更改)。

mutable int i;

(A*)this ->i++; //将当前const指针转成非const指针,然后更改。这时候,const称为是按逻辑const, 通常的const是按位const。

2 const 修饰类的数据成员。

 const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的(因类的不同对象其const数据成员的值可以不同)。不能在类声明中初始化const数据成员,只能在类的构造函数的初始化表中进行(因类的对象未被创建时,编译器不知道const 数据成员的值是什么)。

class A

{

   public:

       A(): i(10) //必须在这初始化因为这是没有调用构 造之前唯一可行的地方

       {

   i = 10; //错误,不能二次初始化const 第一次也不能在这里

}

  private:

      constint i = 10; //不能在这里初始化

      staticconst int j  = 11; //这是合法的,且只能在这里初始化,因为:类里的static表示类中只有一份,在类中任何//构造函数之前就必须存在,这是编译期间常量,保存在符号表里

}

1)不能在类声明中初始化const数据成员,只能在类的构造函数的初始化表中进行

class A

{

      constint size = 100;     //错误

      intarray[size];          //错误,未知的size

}

2const数据成员的初始化。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现。枚举常量不会占用对象的存储空间,他们在编译时被全部求值。但是枚举常量的隐含数据类型是整数,其最大值有限,且不能表示浮点数。

class A

{

      enum{size1=100, size2 = 200 };

      intarray1[size1];

      intarray2[size2];

}

 

三、const作用域范围      

在全局作用域声明的 const 变量是定义该对象的文件的局部变量。此变量只存在于那个文件中,不能被其他文件访问。

通过指定 const 变更为 extern,就可以在整个程序中访问 const 对象在另一连接文件中引用const常量时不能再次赋值。

      // file_1.cc
      extern const int bufSize =fcn();
      // file_2.cc
      extern const int bufSize; // usesbufSize from file_1
      for (int index = 0; index !=bufSize; ++index)
            // ...

本程序中,file_1.cc 通过函数 fcn 的返回值来定义和初始化 bufSize。而 bufSize 定义为 extern,也就意味着 bufSize 可以在其他的

内容概要:本文档为《400_IB Specification Vol 2-Release-2.0-Final-2025-07-31.pdf》,主要描述了InfiniBand架构2.0版本的物理层规范。文档详细规定了链路初始化、配置与训练流程,包括但不限于传输序列(TS1、TS2、TS3)、链路去偏斜、波特率、前向纠错(FEC)支持、链路速度协商及扩展速度选项等。此外,还介绍了链路状态机的不同状态(如禁用、轮询、配置等),以及各状态下应遵循的规则和命令。针对不同数据速率(从SDR到XDR)的链路格式化规则也有详细说明,确保数据包格式和控制符号在多条物理通道上的一致性和正确性。文档还涵盖了链路性能监控和错误检测机制。 适用人群:适用于从事网络硬件设计、开发及维护的技术人员,尤其是那些需要深入了解InfiniBand物理层细节的专业人士。 使用场景及目标:① 设计和实现支持多种数据速率和编码方式的InfiniBand设备;② 开发链路初始化和训练算法,确保链路两端设备能够正确配置并优化通信质量;③ 实现链路性能监控和错误检测,提高系统的可靠性和稳定性。 其他说明:本文档属于InfiniBand贸易协会所有,为专有信息,仅供内部参考和技术交流使用。文档内容详尽,对于理解和实施InfiniBand接口具有重要指导意义。读者应结合相关背景资料进行学习,以确保正确理解和应用规范中的各项技术要求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值