南宁美容网站建设,河南郑州网站建设,南京网站设计制作,现在做外贸前景如何欢迎参与讨论#xff0c;转载请注明出处。前言因为某些机缘巧合#xff0c;引起了我对C的重视。一时兴起#xff0c;决定将两年前用Unity写的Snake进行移植。经过两周的抽空#xff0c;总算是完成了。项目采用现代C标准编写#xff0c;采用CMake构建#xff0c;图形库为S…欢迎参与讨论转载请注明出处。前言 因为某些机缘巧合引起了我对C的重视。一时兴起决定将两年前用Unity写的Snake进行移植。经过两周的抽空总算是完成了。项目采用现代C标准编写采用CMake构建图形库为SDL。由于本次的重点不在于图形这块所以没有使用原版的素材采用矩形代替。 在工程实现上除了基本的业务外还实现了C#的event以及的Unity的GameObject与Component。 本文将从C#开发者的角度出发比较C的不同点最后总结其思想。由于本人在此之前从未有C的工程经验对于许多特性在此之前也是一知半解对于一些事物的理解若有误还请指教。低成本封装首先最引我瞩目的便是C的参数传递形如这般的函数void Init(const string title, int width, int height);由于C的引用参数string性质将值传入时不会发生拷贝而是等于直接使用原变量。可以有效降低封装抽象的成本加上const字段是为使得形如123这样的常量区对象也能传入。 当然这在C#也并不是没有ref便是如此。但这在C#并不会下意识去用毕竟在C若是不用指针或引用作为参数的话可是会直接拷贝新对象的而在C#直接使用也不会造成很大的负担值类型直接拷贝引用类型用指针。 其次便是C的内联函数了作为函数宏的替代品之一。可以在编译时将函数展开为具体的内容节省了一次函数调用的消耗。但内联函数需写在头文件中若是关联项多修改后便会增加编译时长。且展开量过大也会增大代码量增加编译时长。但不失为一个降低封装成本的手段。明确的内存其次与C#最大的不同便是对象的创建了C有着以下两种形式A a A();
A* a new A();
了解C的自然晓得前者在当前内存域下申请后者在堆申请。而在C#则隐去了这个细节而是设立固定的规则引用对象使用指针原则上在堆申请若对象的生命周期存在于申请的函数里则在栈申请——是为逃逸分析。值对象在当前内存域下申请且由于不是指针变量传递会产生拷贝。除非使用ref、in、out等参数关键字。 而C的内存申请机制则带来了明确感如在函数里申请生命周期只存在函数里的对象需要明确的使用A a A();方式。且在构建类的时候对于那些不使用A* a new A();创建方式的成员变量其内存占用是明确的在类对象申请内存的时候会一并申请即这些成员变量在内存布局上可能是连续的。从这点来说可比C#要牛逼多了。相似的容器 在容器方面C与C#大体看起来是相似的当然在API的爽度而言还是C#更胜一筹C17拉近了不少。但实际上还是存在一些细节上的不同就比如我们常用的Key-Value容器C的std::map与C#的Dictionary在实现乃至功能上就不一样。实际上std::map对应C#的应该是SortedDictionary它们都是基于红黑树实现都是有序存储的表。而Dictionary则是基于哈希实现的即我们俗称的哈希表与之对应的是std::unordered_map。 通过命名能看出两种语言在这方面的倾向性红黑树占用的内存更小但查找和删除的时间复杂度都是O(logn)而哈希查找和删除的时间复杂度都是O(1)。实际使用的时候感觉还是得权衡利弊不能贪图方便就一直用一套。std::set与HashSet这边也是类似的对应以此类推。 在序列容器方面的对应倒是工整std::vector对应List都是不断扩容的数组容器。链表方面则是std::list对应LinkedList。但std::array却无对应了硬要说的话就是与C#的原生数组对应毕竟这个容器出现的意义就是弥补与C语言兼容的原生数组。 顺带一提在使用std::vector时由于会出现扩容复制的问题需要考虑好成员对象的拷贝方案乃至于内存泄漏的问题。智能的指针 内存管理是所有编程语言都无法绕开的点绝大多数编程语言对于堆内存的管理都是采用垃圾回收的方式。而在C的鸿蒙时代则与C语言一样需要手动管理指向堆内存的指针。尽管也有std::auto_ptr这样的东西但在功能上还不够全面。而手动管理内存将难以解决对象在多处被引用时将如何安全销毁的问题为了实现这种机制也得做出不少妥协。 所幸随着时代的发展现代C迎来了智能指针它基于引用计数的规则将裸指针包装起来当符合销毁条件后便可自动回收。智能指针有着几种具体的类实现而其中最常用的是std::share_ptr当它持有指针时将增加计数反之同理将减少计数最终归0销毁。但其较之垃圾回收有个致命的缺陷相互引用时将一直保持计数无法销毁。为此C引入了std::weak_ptr它不会增加计数在计数归0时持有指针也随之销毁。如此对于相互引用的情况下分清主次合理分配share_ptr与weak_ptr即可解决无法销毁的问题。 智能指针在使用上总有一种外挂的感觉需要成体系的去使用。不如内置的垃圾回收式语言来的方便且写起来还是有一定的心智负担相互引用不过在性能而言较之垃圾回收更为优越回收对象与时机都很明确且是被动进行的。模板与泛型C的模板与C#的泛型表面上用起来很是相似实则有所不同。以下对比两者的差异templateclass T, int x // C支持模板参数可填写整型或指针
GenericListT where T : Employee // C#使用System.Object不支持的方法时需进行类型约束指定基类
// 这么骚的操作见过么
void f(int x);template class ... Args
void Do(Args... args) {f(args ...);
};从实际使用体验与两者的命名可以看出「模板」的本质是参数化代码生成而「泛型」则是类型参数化。即泛型只是模板功能的一部分而已。模板能实现的其他功能在C#则以其他方式代替了如变长参数params。后记 从以上种种便能看出C与C#在设计哲学上的不同C#通过约束开发者行为从而达到更稳定健壮的结果哪怕会失去一定的性能与灵活性而C则更依赖开发者自身的素质如C支持多重继承而C#仅仅支持单类多接口继承。 从个人的使用体验来看现代C并非不能作为业务开发语言。只是对开发者的素质要求较之一般语言更高从招聘成本与项目稳定性而言是个问题。如此来看除非有必要的性能敏感且需要一定封装的核心层如游戏引擎否则用C 脚本语言或者C#/Java这类可上可下的语言是个更好的选择。