C++对C的增强

前言

​ C++中对于C语言的关键词是有强化,在之前的文章中,我们提到了C中的const修饰是假,可以通过指针指向被修饰的const变量来对const变量进行修改。

这个是一个测试代码,有兴趣的朋友可以复制进行测试。注意这里使用编译器为C语言编译器,并且文件的后缀为.c的后缀。

#include<stdio.h>
int main()
{
    const int test = 100;
    int *p = NULL;
    p=(int *)&test;
    *p = 200;
    printf("%d",test);
    return 0;
}

​ 得到的结果是test被修改为200,说明通过指针对const的变量的进行修改是可行的,但是如果使用C++语言编译器,则得到的结果为test为100,这个结果表明了在C++中const的处理机制和C语言的处理进制是不同,并且是一个“真实的”const。通过这个测试我们得到以下两个结论:

  • C的const变量是一个常变量,变量的值可以间接修改。
  • C++中const是一个真正的常量,不可以进行修改。

那么通过这个现象,我不由的疑惑:

​ 如果C++的变量是一个真正的常量,那么为什么我们使用C++的指针对常量尽心修改的时候,编译器没有报错,正常而言,编译器应该出现错误,最差也应该出现waring警告了。从这个现象我们可以得到结论:C++的编译器认为这种语法是成立的,可能是为了兼容C编译器的原因。但是这种有一个问题,既然C++编译器认为这种语法是成立,但是为什么最后的结果没有改变test的值。

底层原理分析

​ C++编译器在扫描到常量的声明时候,它不会像C语言的编译器那样,给const单独分配一个内存。在C++的编译器中,遇到const会做以下几个工作。

  • 检查到const int test = 100;语句,C++编译器先将变量test放置到一个符号表中(键值对),必须注意的是,这个时候是没有分配内存的。但是符号表是确定的,没有分配内存,符号表具体的实现和我们的常说的堆栈不是同一套的实现方式。当你使用这个test,编译器会从符号表中将对应的值取出给你进行使用。
  • 遇到 p=(int *)&test;这种语句的时候,也就是当你对test常量取地址的时候,C++编译器会对test单独开辟一个地址,然后将这块内存的地址赋值给p,这个时候使用p去间接修改内存的地址,这个修改式新分配的地址。但是我们符号表中的键值对是没有改变,所以test的值是没有改变,并且指针也是一个安全区域的指针,所以C++编译是没有错误和警告的。
#include<stdio.h>
int main()
{
    const int test = 100;
    int *p = NULL;
    p=(int *)&test;
    *p = 200;
    printf("%d\r\n",test);
	printf("%d\r\n",*p);
    return 0;
}

得到数据是100 和 200 所以结论是正确的。

补充说明

​ C++中那个const的分配内存是在什么时候分配的呢?是在编译器编译阶段,还是在执行阶段分配

​ C++中const分配内存的时机,是在编译期间!

#include<cstdio>
int main()
{
    int a;
    const int b=98;
    int c;
    printf("&a=%d\n",&a);
    printf("&b=%d\n",&b);//用了取地址 
    printf("&c=%d\n",&c);

    return 0;
}

结果表明:
const int b的地址在a和c之间,符合我们局部变量申请内存的压栈的顺序它并没有因为,&b这句话写到int c后面,就先分配a,c最后才b,而是,它扫描完之后,看到这里有&b了,就分配地址了。

posted @ 2023-06-28 00:21  Kroner  阅读(26)  评论(0编辑  收藏  举报