C++语法中const到底是什么情况?

const的用法

如何理解const:
const修饰的变量不能再作为左值。初始化以后,值不能被修改。

1.C和C++中的const的区别是什么?

1.初始化

C++的const变量一定要初始化

C的const变量可以不要初始化

2.常量

C++的const变量是常量,,由编译器来将出现常量的地方用其初始值替换。因此可以用来创建数组。但是如果用变量来初始化const常量,那么也会退化成常变量。

C的const变量是常变量,只是把其看作一个变量来生成指令,但是会检测用户对其的修改。因此不可以用来创建数组,且可以被修改(见3)。

int main() {
    const int a=10;
    /*
    CPP里面是可以的
    C里面是不可以的
    */
    int arr[a] = {};
    return 0;
}

3.const修饰的变量,我能不能通过其指针对其修改?

  • CPP文件里面:

    //main.cpp
    int main() {
        const int a=10;
        int* p = (int*)&a;
        *p = 30;
        printf("%d %d %d \n", a, *p, *(&a));
        return 0;
    }
    
    /*
    输出结果:
    10 30 10;
    */
    

    其汇编指令如下

    const int a=10;
        00007FF6397C500D  mov         dword ptr [a],0Ah 
        # 给a赋值
    int* p = (int*)&a;
        00007FF6397C5014  lea         rax,[a]  
        00007FF6397C5018  mov         qword ptr [p],rax  
        # 指令把a的地址赋值给了p
    *p = 30;
        00007FF6397C501C  mov         rax,qword ptr [p]  
        00007FF6397C5020  mov         dword ptr [rax],1Eh  
        # 指令通过p修改了a的内容
    printf("%d %d %d \n", a, *p, *(&a));
        00007FF6397C5026  mov         r9d,0Ah  
        # 获取a的值
        00007FF6397C502C  mov         rax,qword ptr [p]  
        00007FF6397C5030  mov         r8d,dword ptr [rax]  
        # 获取了*p的值
        00007FF6397C5033  mov         edx,0Ah  
        # 注意此处:直接把10赋值给edx,而并不是从a的地址处取值。
        00007FF6397C5038  lea         rcx,[string "%d %d %d \n" (07FF6397CACA8h)]  
        00007FF6397C503F  call        printf (07FF6397C11B3h) 
    
  • C文件下:

    // test.c文件
    #include<stdio.h>
    void main() {
        const int value = 10;
        int* ptr = (int*) &value;
        *ptr = 321;
        printf("%d %d %d\n", value, *ptr, *(&value));
        return 0;
    }
    /*
    显示结果:
    321 321 321
    */
    

    其汇编指令如下:

    const int value = 10;
        00007FF6A5D31A0D  mov         dword ptr [value],0Ah  
    int* ptr = (int*) &value;
        00007FF6A5D31A14  lea         rax,[value]  
        00007FF6A5D31A18  mov         qword ptr [ptr],rax  
    *ptr = 321;
        00007FF6A5D31A1C  mov         rax,qword ptr [ptr]  
        00007FF6A5D31A20  mov         dword ptr [rax],141h  
    printf("%d %d %d\n", value, *ptr, *(&value));
        00007FF6A5D31A26  mov         r9d,dword ptr [value]  
        00007FF6A5D31A2A  mov         rax,qword ptr [ptr]  
        00007FF6A5D31A2E  mov         r8d,dword ptr [rax]  
        00007FF6A5D31A31  mov         edx,dword ptr [value]  
        # 此处是从value的地址获取数据,而不是编译器优化直接用数据替代
        00007FF6A5D31A34  lea         rcx,[string "%d %d %d\n" (07FF6A5D3AD28h)]  
        00007FF6A5D31A3B  call        printf (07FF6A5D3119Ah)  
    

总结:

由此可见,对指针进行修改是可以的,但是编译器对代码进行了优化,会直接用const变量的值来替换此处的*(&value)。

3.思考

那么再思考:(看完3的汇编再来看这个)

1.如果我用变量来初始化const常量会怎么样?

2.上述情况下,再通过指针修改const会怎么样?

答:可以,因为退化成了常变量

//问题一:如果我用变量来初始化const常量会怎么样?
int a = 20;
const int b = a;
//如果修改a的值,那么b变化吗?
cout << a << " " << b << endl; // 20 20
a = 30;
cout << a << " " << b << endl;// 30 20.此处还是被20替换

//如果通过const创建数组呢?
int arr[b]={0};//编译不通过
//问题二:上述情况下,再通过指针修改会怎么样?
int main() {
    int a = 20;
    const int b = a;
    //如果修改a的值,那么b变化吗?(不会)
    cout << a << " " << b << endl; // 20 20
    a = 30;
    cout << a << " " << b << endl;// 30 20.此处还是被20替换
    //此使再通过指针修改const可以吗?(可以,退化成了常变量)
    int* p = (int*)&b;
    *p = 99;
    cout << a << " " << b<<" "<<*p << endl;//30 99 99
    return 0;
}

2. const和一级指针的结合

2.1 const指针类型

C++语言规范:const修饰的是离它最近的类型

  1. const int * p;

    此处const修饰int 因此*p不可以变

  2. int const * p;

    *无法单独作为一个类型,因此此处const还是修饰int 同上

  3. int * const p;

    可以作为一个指向int类型的指针,因此const修饰int *。因此p不可变,*p可以变

  4. const int * const p;

    前面一个const修饰int*;后面一个const修饰 int* 。因此均不可变。

类型const int * pint const* pint *const pconst int * const p
修饰谁const修饰int* 不能作为一直类型,因此还是修饰 intint *表示指向整型的指针 因此修饰int*前面的修饰int,后面修饰int *
可以的语法const int* p = &a; p = &b;可以对p进行重新赋值同左int* const p = &a; *p = 10086;可以通过p修改原数据
不可以的语法const int * p = &a;*p = 100;不能通过p修改数据同左const int* p = &a;p = &b; 不可以修改pconst int* const p = &a; p = &b; *p = 10086; 无论是修改p还是修改* p都不可以

2.2const指针转换

一级指针的时候

  1. int * —> const int * 是可以的

  2. const int * —> int * 是不可以的

二级指针的时候(先看后文)

  1. const修饰的是int

    • const int ** —>int **是错误的
    • int ** —> const int ** 也是错误的
  2. const修饰的实际上是int*

    • int* const * —> int** 是错误的
    • int** —> int * const * 是正确的

:int* const p 能不能把p赋值给int *类型?

答案:可以

int a = 99;
int* q = &a;
cout << typeid(q).name() << endl; //int * __ptr64
cout << endl;

const int* const p = &a;
cout << typeid(p).name() << endl;//int const * __ptr64
cout << typeid(&p).name() << endl;//int const * __ptr64 const * __ptr64
cout << endl;

int const* pp = &a;
cout << typeid(pp).name() << endl;//int const * __ptr64
cout << typeid(&pp).name() << endl;//int const * __ptr64 * __ptr64
cout << endl;

int* const ppp = &a;
cout << typeid(ppp).name() << endl;//int * __ptr64 注意:const不参与类型

int* a1 = ppp;//因此相当于int* 赋值给int *

2.3总结

  1. const如果右边没有指针*,const是不参与类型的
  2. 含有const的变量,其指针类型为在const右边加*
  3. 含有const的指针变量,解地址的类型是在const右边去一个*。

3. const和二级指针的结合

为什么不能从int ** 转换为 const int **
假设可以。

int main() {
    int value = 10;
    int* p1 = &value;
    int** pp1 = &p1;
    const int** pp2 = (const int**)pp1; // 假设这个转换是合法的
    const int newValue = 20;
    *pp2 = &newValue; // *pp2 是 const int* 类型
    *p1 = 30;  // 修改 value 通过 p1, 但 p1 应该指向 const 数据
    return 0;
}

如果 const int** pp2 = (const int**)pp1; 这行代码合法,那么通过 pp2 我们可以将 p1 指向 const int 类型的 newValue。然而,因为 p1 实际上是 int* 类型,我们最终可以通过 p1 修改它所指向的 newValue 的值,这显然违反了 const 的约束。因此,为了避免这种类型的安全隐患,C++ 标准不允许这样的转换。

正确做法:
如果你需要持有一个指向 const int 的指针的指针,应该直接从 const int 开始:

const int value = 10;
const int* p1 = &value;
const int** pp1 = &p1;
  • 12
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值