• C到C++的升级


    C和C++的关系

    • C++继承了所有C语言的特性;
    • C++在C的基础上提供了更多的语法和特性,C++语言去除了一些C语言的不好的特性。
    • C++的设计目标是运行效率与开发效率的统一。

    变化一:所有变量都可以在使用时定义

    C++中更强调语言的实用性,所有的变量都可以在需要使用时定义。我们都知道C语言都必须要在作用域之前的位置定义,否则会报错。

    引申概念,什么是作用域?
    通常我们在写代码的时候,所用到的名字并不是有效/可用的,限定变量或者函数的名字的可用性的代码范围就叫作用域。全局变量作用域就是整个文件,加了extern声明之后作用域就可以为整个工程空间使用。局部变量的作用域就是本函数内,用完即丢弃。
    范例:

    #include 
    #include 
    int main(void)
    {
        int c = 0;
        printf("Begin...\n");
        for(int i=0; i < 10; i++) //在C语言中,变量定义需要在函数开始,不能在使用的地方定义。
        {
            for(int j = 0; j < 10; j++)
    	    {
    	        c += i*j;
    	    }
        }
        printf("c = %d\n", c);
        printf("End...\n");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    C++编译器也可以编译C代码,通过Dev-C++软件分别创建C工程和C++工程,C++工程可以编译pass,C工程报错如下:
    在这里插入图片描述
    注意,使用ubuntu gcc编译能编译通过,因为Dev-C++ 的C编译器和GUN gcc 编译器遵循的标准不一样。GUN gcc 对标准C进行了扩展。

    变化二:register关键字变化

    • C语言中,register这个关键字请求编译器尽可能的将局部变量存在CPU寄存器中,而不是通过内存寻址访问,以提高效率。
      注意是尽可能,不是绝对。因为,如果定义了很多register变量,可能会超过CPU的寄存器个数,超过容量。
      C语言中无法取得register变量地址
    • 在C++中依然支持register关键字。为了兼容C语言特性。
      C++编译器有自己的优化方式,不使用register也可能做优化。
      C++中可以取得register变量的地址,当C++编译器发现程序中需要取register变量的地址时,register对变量的声明变得无效。
      早期C语言编译器不会对代码进行优化,因此register变量是一个很好的补充。
    #include 
    #include 
    int main(void)
    {
        register int c = 0;
        printf("Begin...\n");
        
        printf("&c = %08X\n", &c);
        
        printf("End...\n");
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Dev-C++编译器编译C工程报错提示
    GUN gcc 编译报错
    说明标准C不支持对register取地址。VC++6.0有警告,但是也可以获取寄存地址,只是说明编译器对register变量有处理,申请不掉register变量就变成普通变量。但是标准C是不支持的。
    Dev-C++ 编译C++工程可以编译通过,并打印register变量地址

    变化三:同名的全局变量处理

    • C语言中,重复定义多个同名的全局变量是合法的,最终会被链接到全局数据区的同一个地址空间上。
    • 在**C++**中,不允许定义多个同名的全局变量,C++拒绝这种二义性的做法。
    #include 
    #include 
    int c = 1;
    int c;//加上extern 关键字,C++可以编译通过,表示在前面定义的。
    int main(void)
    {
        printf("Begin...\n");
        
        printf("&c = %08X\n", &c);
        
        printf("End...\n");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    Dev-c++编译报错

    变化三 const 常量

    • 在C中,const修饰的变量是不允许再次赋值的,但是可以通过指针操作const变量。const变量是只读变量,有自己的存储空间。
    #include 
    //const int c = 0;// const修饰全局变量,不可用指针操作修改值,会出现段错误。
    int main(void)
    {
    	const int c = 0;
        int *p = (int*)&c;
    	*p = 8;
        printf("c=%d\n", c);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    GUN编译验证结果

    • 在C++中,编译器对const常量处理:
    1. 当碰见const声明时,在符号表中放入常量;
    2. 编译过程中若发现使用常量,则直接以符号表中的值替换;
    3. 编译过程中若发现对const使用了extern或者&操作符,则给对应的常量分配存储空间。
      Notice:C++编译器虽然可能为const常量分配空间,但不会使用其存储空间中的值。
      如果再到上面的代码中插入打印C常量地址操作
    printf("c address = %08X\n", &c);
    
    • 1

    最终打印如下:
    c=0
    c address = EB6F729C

    C++编译器处理const常量示意图

    • C中const变量是只读变量,告诉编译器该变量不能出现在赋值符号左边,本质是变量,有自己的存储空间。
    • C++中const 是真正的常量,当const常量为全局,并且有extern关键字,或者使用&操作符取const常量地址时,才会分配地址空间。
      为什么C++还要为const 常量分配地址空间呢?因为为了兼容C。

    范例,加强const常量c和c++的理解:

    #include 
    int main(int argc, char *argv[])
    {
    	const int a = 1;
    	const int b = 2;
    	int array[a + b]={0};
    	int i = 0;
    	for (i = 0; i < (a+b); i++)
    	{
    		printf("array[%d] = %d\n", i, array[i]);
    	}
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    分别用gcc 和 g++编译运行结果:
    在这里插入图片描述
    C编译器直接报错,无法确定数组array的大小,因为const在c中本质是变量,编译器无法知道数组array的大小,变量只有在运行时候才知道值。
    C++编译器作为常量处理,直接到符号表中取值,所以array[a+b] 就是array[1+2].
    C++中的const小结

    • const常量类似于宏定义,const int c = 0; ≈ #defin c 5
    • c++中的const常量与宏定义不同
      const 常量是由编译器处理的,提供类型检查和作用域检查。而宏定义由预处理器处理,简单的文本替换。

    范例:

    #include 
    void f()
    {
        #define a 3 //本意是想在本函数中使用a,作用域是该函数
    	const int b = 4;//该变量作用域为f函数
    }
    
    void g()
    {
        printf("a = %d\n", a);//但是预编译器会直接替换掉a.
    	printf("b =d %d\n", b);//编译会报错,因为编译器会对作用域进行检查
    }
    
    int main(int argc, char *argv[])
    {
        f();
    	g();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    变化四:struct类型的变化

    • C语言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型。
    • C++中的struct是一个新类型的定义声明。
    #include 
    struct Student
    {
        const char* name;
        int age;
    };
    
    int main(int argc, char *argv[])
    {
        Student s1 = {"Tom", 30};
    	Student s2 = {"Tony", 28};
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    C和C++编译结果
    C编译器认为Student 不是一个类型,所以报错。C++认为是一种新的类型,可以直接赋值。

    • C++中所有的变量和函数都必须要有类型。
    • C语言中的默认类型在C++中是不合法的。
      范例:
    #include 
    f(i) //C语言默认类型 int f(int i)
    {
        printf("i = %d\n", i);
    }
    g() //c语言默认类型 int g()
    {
        return 5;
    }
    
    int main(int argc, char *argv[])
    {
        f(10);
    	printf("g() = %d\n", g());
    	//printf("g() = %d\n", g(1, 2, 3)); //在C中,这里打开也能编译通过。反之在C++中fail。
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    在这里插入图片描述
    在C语言中,f(i) 和g()函数默认为 int f(int i) 和 int g();
    g() 函数在C中可以接受任意的参数,所以在调用的地方写g(1,2,3)也能通过,只不过对传入的参数不处理。
    如果C语言中想要表示不接受任何参数,则需要在函数括号中加void。

    思考,int f();与int f(void); 的区别是什么?

    • C语言中,int f();表示函数可以接受任意的参数,而 int f(void);表示调用时不接受任何参数否则就报错。
    • C++中,int f();和int f(void) 都相同,表示函数不接受任何参数。对类型检测加强。

    变化五:布尔类型

    在C语言中,我们一般习惯用int 类型替代bool类型使用,用0 表示false,用1 表示true。
    C++ 在C语言的基本类型之上增加了bool类型,且bool可取的值只有true 和 false。

    • 理论上bool类型只占用一个字节(sizeof bool类型,值为1),如果多个bool变量定义在一起,可能会各占一个bit,这取决于编译器的实现。
    • true 和false变成了关键字,true代表真,编译器内部用1来表示;false代表非真,编译器内部用0来表示。
      范例
    #include 
    int main(int argc, char *argv[])
    {
        int a;
    	bool b = true;
    	printf("b = %d, sizeof(b) = %d\n", b, sizeof(b));//sizeof bool 类型变量1,说明bool类型占用一个字节。
    	
    	b = 3;//编译器在赋值时,将非0值转换为true.
    	a = b;
    	printf("a = %d, b = %d\n", a, b);
    	
    	b = -5;
    	a = b;
    	printf("a = %d, b = %d\n", a, b);
    	
    	a = 10;
    	b = a;
        printf("a = %d, b = %d\n", a, b);
    	
    	b = 0;//编译器在赋值时,将0值转换为false.
    	printf("b = %d\n", b);
    	
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述

    • C++中bool类型更安全,只有真正意义的true 和false。
    • C++编译器会在赋值时,将非0值转换为true,0值转换为false。
    • 我们知道在C语言中,只要是非0值都可以代表true。

    范例:bool 类型变量参与运算

    #include 
    int main(int argc, char *argv[])
    {
    	bool b = false;
    	printf("b = %d\n", sizeof(b));
    	b++;
    	printf("b = %d\n", sizeof(b));
    	b = b+1;
    	printf("b = %d\n", sizeof(b));
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    用GUN g++ 会报错,在新的gun g++编译器中,禁止bool类型进行自加
    1-8.c:6:9: error: use of an operand of type ‘bool’ in ‘operator++’ is forbidden in C++17
    dev C++ 运行结果如下:
    在这里插入图片描述

    变化六:三目运算符

    #include 
    int main(int argc, char *argv[])
    {
    	int a = 1;
    	int b = 2;
    	(a < b ? a : b) = 3;//三目运算符作为左值,然后刚给三目运算符赋值
    	//(a < b ? 8 : 6) = 3; //用g++ 编译器也会报错,因为这里返回的是常量,常量不能放在赋值符号左边。
    	//(a < b ? 8 : b) = 3;//用g++ 编译器也会报错,因为这里返回值中有常量。
    	printf("a = %d, b = %d\n", a, b);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • C语言中,三目运算符返回的是值,而不是变量本身。不能放在赋值符号左边。
    • C++中,返回的是变量本身。因此可以放在赋值符号左边,同时也可以放右边。
      注意:三目运算符如果可能的返回值中有一个是常量,则不能作为放在赋值符号左边。
      gcc编译结果
      g++编译运行结果
      思考,C++ 对三目运算符做了什么处理?
      变量名回顾:
    • 变量是一段实际连续存储空间的别名;
    • 程序中通过变量来申请并命名存储空间;
    • 通过变量的名字可以使用存储空间。

    对于一段连续的存储空间,只能有一个别名吗?

    总结

    • C++ 以C语言为基础,进行了加强。
    • C++更强调实用性,可以在使用的时候声明变量,不需要在函数开头。
    • C++中register只是向C兼容,C++编译器能够进行更好的变量优化。
    • C++中的const是一个真正意义的常量,而不是只读变量。
    • C++更加强调类型,任何函数和变量都必须要指明类型。
    • bool 类型是C++新增加的基础类型,其值只能是true 和 false。
  • 相关阅读:
    【STM32】两个版本MDK搭建和三种调试器的使用
    第十三届蓝桥杯省赛JavaA组 H 题,JavaC组 I 题—— 因数平分和 (AC)
    Qt-OpenCV学习笔记--高级形态转换--morphologyEx()
    随便给你一个页面 你该如何去给他布局呢 各位思考一下 ?
    K8s: 在Pod中将configmap数据注入容器
    Linux下安装MySQL8.0的详细步骤
    CSDN21天学习挑战赛之折半插入排序
    高效搜索,提升编程效率
    Linux中in、ls、tree、clear的用法
    客户端缓存技术
  • 原文地址:https://blog.csdn.net/u014106791/article/details/132642320