C++语言到底是不是C语言的超集之一
wptr33 2025-04-27 16:41 12 浏览
C与C++两个关系亲密的编程语言,它们本质上是两中语言,只是C++语言设计时要求尽可能的兼容C语言特性,因此C语言中99%以上的功能都可以使用C++完成。本文探讨那些存在于C语言中的特性,但是在C++中缺失或者表现出不同行为的特性。了解这些特性能让你更深入地理解这两个语言,但是,本文中所罗列的每一项特性都不是建议你在程序开发中采用的技巧,而恰恰相反是应该避免使用的特性。为了你的代码可读性更好,移植性更强,请不要在你的代码中的任何地方秀出这样的特性。了解它是为了更好地避免她。
C++语言类型检查更强
C语言的类型检查比C++要弱,比如在C语言中void*类型就可以被赋值给char*类型,虽然二者不是同一个类型,甚至二者实际为完全不同的类型,如下图1中的代码,首先定义一个整型变量a,之后使用void指针p1指向整型变量a的地址;再通过char指针p2指向p1,在下图中的第19和20行代码,C编译器是没有提供任何错误的,对于C语言来说,一切都很合理。
但是对于C++编译器来说,void类型的指针是不能够直接赋值给char类型指针的,如上图1中的做法,C++编译器会毫不留情地抛出错误,如下图2所示
对于C++来说,将void*类型的变量赋值给char*的变量,必须显式地指定转换意图,编译器是不会自动为你转换的,他只知道你要把两个不同的东西搞到一起,对他来说是不可接受的。显式地转换类型可以实现你的意图,如图3第20行代码所示,通过使用static_cast类型转换表达式实现转换为目标变量的相同类型。
指针限定符(qualifier)
对于无限定符的指针来说,它不允许或不建议将无限定符的指针赋值给含有限定符的指针,图4中代码,第4行代码为无限定符的指针,第5行代码为含有一个限定符的指针,第6行代码为含有两个限定符的指针。
使用C编译器进行编译图4中的代码时,编译器给出了如下的警告信息,它提示了你进行了两种不兼容类型的指针转换,使用的时候要小心了,出现什么问题自己要负责。
但是,对于C++编译器来说,使用如图6所示的代码。
编译时给出的错误就是如下图7的情景了,图6中第5行代码是合法的,但是第6行代码对于C++编译器来说就是个错误了,它不允许你将int**转换为const int**类型。
枚举类型处理方式
C语言中枚举类型和整型之间的变量进行赋值时,直接使用就是了,整型值可以直接赋值给枚举型变量,同样,枚举值也可以直接赋值给整型变量,如下图8所示的代码。
第6行代码定义一个int类型变量c1,并将其初始化为一个枚举类型的枚举值green,之后通过第9行代码,又将枚举型变量c2赋值给整型变量c3。这两条语句对于C语言来说都是正确的。
但对于C++来说,编译器则不可接受!两种不同类型的变量怎么能够相互赋值呢!如图9所示,它不支持直接将一个整型类型的数值赋值给一个枚举类型的变量。
如果想要在C++中正常地将整型数组赋值给一个枚举变量,那么它需要显示地指定转换目标变量的类型,同样我们可以使用static_cast转换表达式,如图10所示,显示地指定转换后的类型为color枚举值。
常量初始化
C语言中通过const限定符修饰的变量是可以不用指定初始值的,比如下面的代码声明了一个变量i,但是它在类型int前面使用了限定符const,使用C语言编译器编译此代码时,一切正常。
但是如果使用C++的话,使用const限定符的变量必须指定初始化值,否则编译器报如下错误。
虽然不知道C语言这样设计是为什么,也不知道没有初始化的变量以后如何设置它的值,但是目前编译器的行为就是这个样子的,怪怪的,不像是个精心设计的功能,反而给人的感觉倒像是个失误似的。
交叉初始化(crossing initialization)
在C语言中你是可以在goto或switch语句中进行交叉初始化(crossing initialization),但是在C++中你是不能够这样做的。如图13中,采用了goto语句(没事不要使用它,破坏结构化编程逻辑),C语言可以正常编译的。
但是C++是禁止这种用法的,它会给出奇怪的错误,如下图14所示。
全局变量的临时定义
C语言支持在同一个翻译单元(translation unit)中临时性地定义一个全局变量,之后你可以再次定义一个同名的变量,而编译器是不会报错的。这个功能又是一个看上去像个Bug的功能,不知道如何使用,也尽量不要使用这偏门左道技术。
图15中第3行代码和第7行代码都定义了一个整型变量age,C编译器会欣然接受它这种写法,但C++编译器就不客气了,认为它是个语法错误,你重复定了这个age变量,直接抛出下图16中的错误,告诉你不要重复定义之前的变量。
struct、union或enum可以同名
你可以使用enum定义一个枚举类型color,之后再通过typedef定义一个类型为color的结构体,这两种类型是可以同时存在的。见图17中的代码
图17中第2行代码定义了一个color枚举类型color,代码第30-34行又定义了一个color类型的结构体,通过第28行代码定义了一个枚举型变量c1表示颜色枚举值,而第36行代码定义了一个结构体颜色变量,两个color表示不同的类型。但是对于C++来说,就是违反了语法规则,编译器会无情地给出如下图18的错误信息
K&R函数定义
虽然C语言的K&R编程风格不被推荐使用,但是,现在的C编译器依旧保留了C语言的这种写法,比如定义一个函数时,可以采用如图19所示
但是,这种写法对于C++编译器来说是不被允许的,会抛出下图中的错误,它可不认识K&R风格的语法。
函数声明
在C语言中,如果函数原型未指定参数,那么它表示这个函数可以接收一个或多个参数,如果表示这个函数没有参数,则使用关键字void表示。如下图21所示
图21中第3行代码定义了一个名称为f的函数,其参数列表为空,它表示此函数对应的定义可以是接收一个或多个参数,本例中为2个参数,它定义在第12-14行代码之间。第4行代码声明了一个函数,其参数为void,表明这个函数的定义中无需任何参数。
对于C++语言来说,这就是个错误,函数的声明与函数的定义类型不匹配!如图22所示编译器给出的错误。但是C++对于参数列表为空和为void的情况处理方式一致,都表示没有输入参数,其与C语言的行为也是不一样的。
嵌套struct
C语言和C++语言中嵌套struct的作用域范围也是不一样的。在C语言中,嵌套C结构的作用范围与其外层定义的结构相同,但是对于C++来说,它的嵌套结构作用域只存在于这个外层作用域之内。如下图23所示的代码
在C语言中,嵌套结构color为第7-11行代码,在使用color结构时,可以与使用其外层的结构person相同,图23中第15行代码和第23行代码分别定义了一个person和color结构,person为外层结构,color则为嵌套结构,虽然color定义在person结构之内,但这并不影响第23行的用法。但它对于C++来说也是错误,如下图所示
变长数组(Variable-Length-Array)
变长数组是在运行时刻分配数组的大小,而不是在编译时刻决定的。C语言中通过在函数中定义一个数组,这个数组的大小可以是一个参数变量,如图25所示
在图25中,第5行代码定义了一个int型的数组,数组的大小为n,注意这个n是一个变量,数组data就是一个变长数组。第15和16行代码,分别使用不同的参数数值调用f函数,f函数第一次调用中data数组的长度为10,f函数第二次调用中它的长度变为了20。虽然说这是C标准中定义的内容,但是测试使用的gcc和g++都可以编译图25中的代码。而微软visual studio 2022对于图26中C代码或C++代码的代码编译时,都给出了编译错误,如图27所示。
从测试的结果来看,微软提供的C/C++编译器目前是不支持变长数组功能的。
至此,我们介绍了C语言中的一部分特性,但是C++语言没有或者表现不相同的实例代码,并给出了C++编译器提供的错误信息,除此之外,C语言中还有一些其它内容与C++语言表现不一致,下一篇文章我们继续聊C语言的个性,谢谢各位,我们下一篇文章见!
相关推荐
- Python自动化脚本应用与示例(python办公自动化脚本)
-
Python是编写自动化脚本的绝佳选择,因其语法简洁、库丰富且跨平台兼容性强。以下是Python自动化脚本的常见应用场景及示例,帮助你快速上手:一、常见自动化场景文件与目录操作...
- Python文件操作常用库高级应用教程
-
本文是在前面《Python文件操作常用库使用教程》的基础上,进一步学习Python文件操作库的高级应用。一、高级文件系统监控1.1watchdog库-实时文件系统监控安装与基本使用:...
- Python办公自动化系列篇之六:文件系统与操作系统任务
-
作为高效办公自动化领域的主流编程语言,Python凭借其优雅的语法结构、完善的技术生态及成熟的第三方工具库集合,已成为企业数字化转型过程中提升运营效率的理想选择。该语言在结构化数据处理、自动化文档生成...
- 14《Python 办公自动化教程》os 模块操作文件与文件夹
-
在日常工作中,我们经常会和文件、文件夹打交道,比如将服务器上指定目录下文件进行归档,或将爬虫爬取的数据根据时间创建对应的文件夹/文件,如果这些还依靠手动来进行操作,无疑是费时费力的,这时候Pyt...
- python中os模块详解(python os.path模块)
-
os模块是Python标准库中的一个模块,它提供了与操作系统交互的方法。使用os模块可以方便地执行许多常见的系统任务,如文件和目录操作、进程管理、环境变量管理等。下面是os模块中一些常用的函数和方法:...
- 21-Python-文件操作(python文件的操作步骤)
-
在Python中,文件操作是非常重要的一部分,它允许我们读取、写入和修改文件。下面将详细讲解Python文件操作的各个方面,并给出相应的示例。1-打开文件...
- 轻松玩转Python文件操作:移动、删除
-
哈喽,大家好,我是木头左!Python文件操作基础在处理计算机文件时,经常需要执行如移动和删除等基本操作。Python提供了一些内置的库来帮助完成这些任务,其中最常用的就是os模块和shutil模块。...
- Python 初学者练习:删除文件和文件夹
-
在本教程中,你将学习如何在Python中删除文件和文件夹。使用os.remove()函数删除文件...
- 引人遐想,用 Python 获取你想要的“某个人”摄像头照片
-
仅用来学习,希望给你们有提供到学习上的作用。1.安装库需要安装python3.5以上版本,在官网下载即可。然后安装库opencv-python,安装方式为打开终端输入命令行。...
- Python如何使用临时文件和目录(python目录下文件)
-
在某些项目中,有时候会有大量的临时数据,比如各种日志,这时候我们要做数据分析,并把最后的结果储存起来,这些大量的临时数据如果常驻内存,将消耗大量内存资源,我们可以使用临时文件,存储这些临时数据。使用标...
- Linux 下海量文件删除方法效率对比,最慢的竟然是 rm
-
Linux下海量文件删除方法效率对比,本次参赛选手一共6位,分别是:rm、find、findwithdelete、rsync、Python、Perl.首先建立50万个文件$testfor...
- Python 开发工程师必会的 5 个系统命令操作库
-
当我们需要编写自动化脚本、部署工具、监控程序时,熟练操作系统命令几乎是必备技能。今天就来聊聊我在实际项目中高频使用的5个系统命令操作库,这些可都是能让你效率翻倍的"瑞士军刀"。一...
- Python常用文件操作库使用详解(python文件操作选项)
-
Python生态系统提供了丰富的文件操作库,可以处理各种复杂的文件操作需求。本教程将介绍Python中最常用的文件操作库及其实际应用。一、标准库核心模块1.1os模块-操作系统接口主要功能...
- 11. 文件与IO操作(文件io和网络io)
-
本章深入探讨Go语言文件处理与IO操作的核心技术,结合高性能实践与安全规范,提供企业级解决方案。11.1文件读写11.1.1基础操作...
- Python os模块的20个应用实例(python中 import os模块用法)
-
在Python中,...
- 一周热门
-
-
C# 13 和 .NET 9 全知道 :13 使用 ASP.NET Core 构建网站 (1)
-
因果推断Matching方式实现代码 因果推断模型
-
git pull命令使用实例 git pull--rebase
-
面试官:git pull是哪两个指令的组合?
-
git 执行pull错误如何撤销 git pull fail
-
git pull 和git fetch 命令分别有什么作用?二者有什么区别?
-
git fetch 和git pull 的异同 git中fetch和pull的区别
-
git pull 之后本地代码被覆盖 解决方案
-
还可以这样玩?Git基本原理及各种骚操作,涨知识了
-
git命令之pull git.pull
-
- 最近发表
- 标签列表
-
- git pull (33)
- git fetch (35)
- mysql insert (35)
- mysql distinct (37)
- concat_ws (36)
- java continue (36)
- jenkins官网 (37)
- mysql 子查询 (37)
- python元组 (33)
- mybatis 分页 (35)
- vba split (37)
- redis watch (34)
- python list sort (37)
- nvarchar2 (34)
- mysql not null (36)
- hmset (35)
- python telnet (35)
- python readlines() 方法 (36)
- munmap (35)
- docker network create (35)
- redis 集合 (37)
- python sftp (37)
- setpriority (34)
- c语言 switch (34)
- git commit (34)