c,客观-c肯定能做到。标准c,一般的说法是没有.我说的是我自己的想法,如果我写过面向对象的代码,类这个术语对用户来说并不陌生!类基本上是面向对象编程的精髓。一个类只不过是成员数据和成员方法的集合,我们可以通过一个指针来访问成员和方法。抽象、继承、多态和重载是类的基本特性。一般来说,c语言是面向过程的函数式编程。用标准c解决问题,不外乎定义结构、公共体、枚举、基本数据类型等。,然后定义一堆函数来访问和操作这些数据。如果你把这些东西分成适当的文件,授予适当的权限。c语言的每个源文件相当于一个类。抽象、多态,并通过使用c99的无类型指针很好地实现。实现继承比较困难,实现思路是用指针访问父对象的成员。重载,c实现更简单!唐我不认为我。;我在这一段虚张声势。objective-c,swift,这两种编程语言,如果想了解一点的话。可以看到这个理论的影子。当然,这两种语言都有专门的编译器。和c实现的面向对象编程是不一样的,综上所述,用c实现面向对象和编程很难,这不是开发者要考虑的。建议不要往这个方向编程。如java、c、swift等,都可以是面向对象的编程:
1.编译器的问题已经被别人解决了;
很多基本功能,根据系统类库已经提供,我们不idon'我不必写信。
swift前景光明,技术更先进。
因为减少了重复语句和字符串操作所需的代码量,所以代码较少;它的使用简化了方法和函数的调用。
swift更快。根据流行的geekbench性能工具的创造者的调查,2014年12月,swift在使用mandelbrot算法的计算密集型任务的性能上已经逼近c的性能。
泛型编程是一种非常常见的编程方法。主要目的是实现静态绑定,使函数可以接受不同类型的参数,并在编译时确定正确的类型。
许多语言都支持泛型编程。例如,在c中,可以使用函数模板和类模板来实现泛型编程。在单一继承的语言中,如java、objective-c或c#,也可以使用similar和nsobject类型进行编程。在具有类型推理功能的编程语言(如swift)中,可以直接使用泛型编程。
但c语言是高级语言编程的基础语言,如何用c语言实现泛型编程确实是个问题。首先,c语言没有支持函数重载,不支持模板类型,所以真的很难实现。
0x01通用指针简介(void*)
void*是c语言中的一种类型。众所周知,在大多数编程语言中,void类型表示所谓的空类型,比如一个函数返回一个空类型void,这是非常常见的用法。
注意:void的返回值并不意味着没有返回值,而是意味着返回一个空类型,这也是为什么你仍然可以在这些函数中使用return语句的原因。只有某些语言中的构造函数和析构函数没有返回值。在这些函数中,不允许使用return语句。它们是显著不同的。objective-c是一种独特的语言,它的类初始化方法是一种普通的方法,返回值是instancetype(当前类的指针类型)。
void*可能有点不为人知。void*可以表示c语言中任何类型的指针。说到底,对于一个存储单元的地址来说,它存储的所谓数据类型只是每次取的字节数不一样,这些存储单元的地址本身并没有什么不同。下面会更好的体现这句话的意思。
void*的大小永远是一个字,就像普通的指针一样。具体大小因机器字长而异,例如32位机器为4字节,64位机器为8字节。
我还没有t在16位8086机上验证了指针的大小,因为8086的地址是20位。有兴趣的可以回去试试。
个人认为指针大小还是16位,因为20位是物理地址,物理地址是从段地址和偏移地址计算出来的。汇编后,c语言中的指针可能只是变成了相对于段地址的偏移地址。毕竟对于8086来说,数据永远在ds段,而代码永远在cs段。(斜体表示未经核实的陈述)
在c语言中,其他常用类型的指针可以自动转换为void*type,而void*type只能强制转换为其他常用类型的指针,否则会出现警告或错误。
关于所谓的void*指向数组有一个特别大的坑,这里直接用代码解释。
voidswap(void*array,intx,inty,intmallocsize){
void*tempmalloc(mallocsize)
memcpy(temp,数组mallocsize*x,mallocsize)
memcpy(数组mallocsize*x,数组mallocsize*y,mallocsize)
memcpy(数组mallocsize*y温度、内存大小)
免费(临时)
}
这是一个经典的交换函数,借助临时变量temp,不过这个函数是通用的,memcpy的用法后面会介绍。需要注意的是,如果array指向一个数组,你可以t直接用amparray[x]或者arrayx来获取指向x元素的地址,因为void*类型的默认指针偏移量是1,和char*一样,对于大多数类型都会造成错误。因此,在使用泛型类型时,我们必须知道它的原始长度。我们需要一个名为mallocsize的int类型参数来告诉我们这个值,并在计算指针偏移量时乘以它。这相当于c编程中的模板类型定义或者java中的泛型参数。
同时要注意void*类型的指针,它可以不要在任何时候被取消参考(或者老师过去叫什么"获取内容"在课堂上?),原因很明显:void类型的变量是不合法的。因此,如果要解引用,必须先将其转换成普通指针。当在数组中使用时,还应该注意解引用操作符优先于加法操作符,所以应该加上括号,如下所示:
inta*(数组mallocsize*x)
这段代码完美体现了c语言编程的丑陋。
0x02sizeof运算符简介
sizeof运算符相信学过c语言的朋友都很熟悉,但知道sizeof是运算符的人不多,返回的类型是size_t类型。sizeof运算符返回类型占用的空间量。这里唯一的要点是,如果你找到一个指针类型或数组名的大小(事实上,数组名是一个指针常量),返回的结果总是一个单词(见上文)。求一个结构类型的sizeof不是简单的结构中各种类型的sizeof之和,而是涉及到内存对齐的问题。我不这里不想介绍了。详情请访问:如何理解struct的内存对齐?-智虎。
0x03memcpy功能简介
memcpy是一个经常和void*一起使用的函数,它的函数原型是:
void*memcpy(void*,constvoid*,size_t)
头文件属于string.h,可以看到,这个函数本身是以void*type作为参数和返回值的,其实很好理解。这是一个赋值和复制记忆的过程。将第二个参数指向的内存复制到第一个参数,复制的字节数由第三个参数指定。当然,第三个参数通常由sizeof运算符获得,它书上没有例子。我还没有我没有研究过返回值,也没有研究过。;我没用过。如果有知道的朋友可以评论一下。
用0x04c语言实现泛型编程
话虽如此,我们还没有t还没有提到泛型编程。但是,如上所述,一般的思路是使用void*type作为泛型指针,然后使用类似于mallocsize的参数来指定占用的内存大小。占用的内存大小是通过sizeof运算符获得的。如果需要赋值,可以使用memcpy函数来完成。下面是一个直接的例子,这是一个通用的快速排序来说明这些问题:
#ifndefcompare_h
#定义比较_h
#包含ltstdio.hgt
#包含jcb.h
intisgreater(void*x,void*y)
intisgreaterorequal(void*x,void*y)
intissmaller(void*x,void*y)
intissmallerorequal(void*x,void*y)
#endif/*compare_h*/
//
//compare.c
//作业调度程序
//
//鲁创作于2017/11/16。
//版权?2017鲁饶威。保留所有权利。
//
#包含比较.h
intisgreater(void*x,void*y){
return*(int*)xgt*(int*)y
}
intisgreaterorequal(void*x,void*y){
return*(int*)xgt*(int*)y
}
intissmaller(void*x,void*y){
return*(int*)xlt*(int*)y
}
intissmallerorequal(void*x,void*y){
return*(int*)xlt*(int*)y
}
//
//quicksort.h
//作业调度程序
//
//鲁创作于2017/11/16。
//版权?2017鲁饶威。保留所有权利。
//
#ifndefquicksort_h
#定义快速排序_h
#包含ltstdio.hgt
#包含ltstdlib.hgt
#包含ltstring.hgt
#包含比较.h
voidquicksort(void*array,intleft,intright,intmallocsize)
#endif/*quicksort_h*/
//
//quicksort.c
//作业调度程序
//
//鲁创作于2017/11/16。
//版权?2017鲁饶威。保留所有权利。
//
#包含快速排序.h
voidswap(void*array,intx,inty,intmallocsize){
void*tempmalloc(mallocsize)
memcpy(temp,数组mallocsize*x,mallocsize)
memcpy(数组mallocsize*x,数组mallocsize*y,mallocsize)
memcpy(数组mallocsize*y,temp,mallocsize)
免费(临时)
}
intquicksortselectcenter(intl,intr){
返回(左侧)/2
}
intquicksortpartition(void*array,intl,intr,intmallocsize){
intleftl
int右r
void*tempmalloc(mallocsize)
memcpy(temp,数组mallocsize*right,mallocsize)
while(左左右){
while(issmallerorequal(arraymallocsize*left,temp)ampampleftltright){
左边的
}
if(左lt右){
memcpy(数组mallocsize*right,数组mallocsize*左,mallocsize)
正确
}
while(isgreaterorequal(arraymallocsize*right,temp)ampampleftltright){
正确
}
if(左lt右){
memcpy(数组mallocsize*left,数组mallocsize*right,mallocsize)
左边的
}
}
memcpy(数组mallocsize*left,temp,mallocsize)
向左返回
}
voidquicksort(void*array,intleft,intright,intmallocsize){
if(leftgtright){
返回
}
中间中心快速排序选择中心(左,右)
交换(数组、中心、右侧、mallocsize)
centerquicksortpartition(数组,左,右,mallocsize)
快速排序(数组,左,中心-1,mallocsize)
快速排序(数组,中心1,右侧,mallocsize)
}
这里有个悬念,明明可以直接比较,何必用很多函数来完成,也就是关于compare.h使用的问题,答案会在下面揭晓。
0x05泛型的协议问题
刚才那个问题涉及到一个通用的协议问题,我借用了objective-c的一个概念在这里详细阐述。就像那个问题一样,既然我的快速排序是泛型的,那我怎么保证传入的实际泛型参数一定是可比较的呢?比如很明显int,float,double是可以比较的,我们也理解char使用ascii编码方案的比较,字符串类型甚至可以比较。但是如何比较其他语言中的对象呢?这是一个问题。在c中,我们可以重载运算符,所以我们仍然可以使用比较运算符,并使用运算符来重载函数。但是java和objective-c呢?而如果传入的泛型参数没有实现对应的运算符重载函数呢?这个时候就会一个协议。简单地说,如果一个类型想要成为一个排序泛型函数的泛型参数,你必须实现一个可比较的协议。这个协议在swift语言中叫做comparable,这样在编译的时候,编译器就会知道这个泛型参数是可以比较的,从而完成我们的操作,否则就会出错。这是泛型中的协议问题。
0x06摘要
c语言的泛型编程以void*为泛型类型,本质上是一个泛型指针。
c语言中的泛型编程需要知道泛型类型变量的内存大小,这可以通过sizeof获得并传递给泛型函数。
在c语言的泛型编程中,要注意数组的偏移量。void*的默认偏移量是1,对于大多数类型来说是错误的,需要自己编程转换。
memcpy函数用于在c语言的泛型编程中复制和赋值泛型变量。
在c语言的泛型编程中,我们也需要注意协议问题,但是在c中,我们只能自己编写函数来定义,可以使用其他语言现成的接口或协议。