龙空技术网

C++语言到底是不是C语言的超集之二

计算机科学技术 543

前言:

此时各位老铁们对“c语言用结构体定义复数”大概比较关怀,各位老铁们都想要剖析一些“c语言用结构体定义复数”的相关资讯。那么小编同时在网络上收集了一些对于“c语言用结构体定义复数””的相关资讯,希望兄弟们能喜欢,我们快快来学习一下吧!

C与C++两个关系亲密的编程语言,它们本质上是两种语言,只是C++语言设计时要求尽可能的兼容C语言特性,因此C语言中99%以上的功能都可以使用C++语言完成。本文探讨那些存在于C语言中的特性,但是在C++中缺失或者表现出不同行为的特性。了解这些特性能让你更深入地理解这两种语言,但是,本文中所罗列的每一项特性都不是建议你在程序开发中采用的奇淫技巧,而恰恰相反地是应该避免使用的特性。为了你的代码可读性更好,移植性更强,请不要在你的代码中的任何地方秀出这样的特性,除非你确认有充足地使用它们的理由。了解它是为了更好地避免它。

C++语言到底是不是C语言的超集之一

复数类型

在C99标准中,定义了内置的复数类型,我们可以使用i表示虚数,如4 - 5i表示一个复数,它的实数部分为4,虚数部分为-5,而且在C语言中,各个复数之间还可以进行数学运算,比如下图1中的代码定义了两个复数,并执行了乘法运算,之后通过函数creal和cimag分别获取计算结果的实数部分和虚数部分。

图1

图1中第2行代码包含了复数相关的头文件complex.h,第5和6行代码分别定义了一个复数变量a和b,注意这两个赋值表达式的右侧值,第8行代码将a和b进行乘法运算,将其计算的结果存放在复数变量c中,最后,使用creal获取复数的实数部分数值,cimag获取虚数部分的数值。

但是,在C++语言中是没办法像这样使用的,它会给出如下的错误信息,C++编译器压根就不认识complex是什么!

图2

如果想要在C++中使用复数,可以使用C++ STL中的complex库,但其用法于C99中的用法是不相同的,图3所示代码实现了与图1相同的功能,如下所示

图3

变长数组

变长数组在C99标准中是允许的,它的用法与声明一个与普通的数组类似,只不过这个变长数组的长度值为一个变量值,而不是普通常量表达式。在下图4中,第4行定义了一个长度为10的普通数组,第10行代码则是定义了一个变长数组,其大小为len变量的值与100之和。

除此之外,变长数组还允许在函数定义和原型中使用,图4中第2行代码为一个函数原型,它的第二个参数为一个变长数组参数,第9行代码定义了对应的函数,这个函数含有两个参数,第二个参数使用了第一个参数len的值作为数组的长度。这样的写法在C语言中都是可以正常编译的。

图4

如果图4中的代码使用C++编译器进行编译代码,它就给出图5中的编译错误

图5

struct的柔性数组成员

在C99标准中定义了结构体柔性数组成员(flexible array member),它是指位于结构体中的最后一个域成员如果是一个数组类型,且这个数组未指定其大小,那么这样的数组就成为了这个结构体的柔性数组成员,如下图6所示

图6

图6中第7行代码为一个柔性数组成员,它是一个位于结构体document中的最后一个域成员,上述的代码并没有指定数组的大小,只给出了数组的类型和名称。在测试代码中,我们分配了一块大小为100字节的内存,这个内存块赋值给了一个struct document类型的指针,整个struct document占据了sizeof(struct document)的大小,其余的空间全留给了这个柔性数组成员,可以像第16-18行代码那样访问内存中的数据。

在C++标准中并没有这样的规定,但是令人惊讶的是gcc(9.4.0)和微软visual studio所使用的C++编译器cl (19.31.31107)都可以正确地支持这样的用法。

restrict关键字

restrict关键字可以作为限定符用在指针声明的地方,它表示的含义为指针所指向的内存只有这么一个指针,不会有其它的指针同时指向它。听着确实够拗口的,看一下下图7中的例子

图7

图7第4-7行代码定义了一个字符串复制函数strcp,它提供了两个参数psrc和pdest,如果将pdest的指针指向psrc内存中的某个位置,那么将会是个灾难性的错误,我们希望psrc和pdest所指向的内存区域为两个互相不重合的内存区域,通过上图7中在定义函数时指定restrict关键字告诉编译器:这两个参数所指的位置互相不重叠,你可以按照自己的意愿对代码进行优化。这就是strict关键字给编译器的提醒。但是,psrc和pdest所指向的内存是否内存重叠,这完全由开发者自己保证,编译器只负责优化代码。

这样的代码在C++中也是不被允许的,它给出的错误信息如下图8所示

图8

函数的参数数组限定符

C99中定义了如果一个函数的参数类型为数组,那么,可以为这个数组添加对应的限定符,下图9演示了数组如何使用限定符。

图9

图9中第4行代码指定f函数的参数类型为char data[const],它的含义与char* const相同,第11行代码中使用了char data[static 10]表示这个数组中的元素的个数至少为10。这样的用法对于C++编译器来说是不允许的,给出的编译错误如下图10所示:

图10

复合字面值(compound literals)

复合字面值是构建一个匿名的结构体、枚举或数组类型的对象,我们通过示例说明,如图11中第4-7行代码定义了一个结构体person,第10行代码定义了一个person结构体对象p1,p1对象的初始化使用了复合字面值,通过大括号{}构建出一个person结构体;第13行代码构建的是一个数组复合字面值,并将这个数组地址赋值给了char类型的指针name;第14行代码也是构建了一个数组复合字面值,但这次对构建的数组执行了取地址运算,并将其赋值给了pname变量。这些用法在C99或C11中分别做了相应的定义,编译器可以正常编译使用。

图11

这样的代码如果使用C++编译器进行编译,那么它会给出下面的出错信息:

图12

Designated initializers

对于数组的designated initializer只允许在C语言中可用,C++就不支持了。下面的代码构建一个数组,并初始化数组的第2元素的值为40,第5个元素的值为40,其它元素为默认值,使用C编译器编译时,一切正常,可以正确地输出10个整数。

图13

但是如果采用C++编译器进行编译,那么它会给出下面的错误信息

图14

noreturn关键字

在C语言中如果一个函数通过特定的系统函数直接退出,而不是返回至此函数的调用点,那么,我们可以给这个函数加上一个关键字noreturn,表示这个函数是不会回到函数的调用点位置的。图15中函数f通过关键字noreturn声明它是不会回到它的调用点第11行代码处,在函数f中第7行代码执行了exit系统函数,C标准库中noreturn支持的函数有:exit、abort、_exit、quit_eixt、thrd_exit和longjmp,如果使用noreturn关键字则必须在这个函数中调用其中的一个。

图15

这样的用法,对于C++来说,同样是不支持的,提供的错误信息如下图16所示

图16

本文为C语言拥有的特性但C++语言所不具备此功能的第二篇文章,二者之间的不同还在继续,下一篇文章我们继续聊C语言的个性,谢谢各位,我们下一篇文章见!

C++语言到底是不是C语言的超集之一

标签: #c语言用结构体定义复数