C#与.Net

最近用C#开发一套独立的编辑器,使用WPF界面框架,引入了Telerik界面库。后来为了让处理数据的逻辑能跨平台运行又创建了一个.Net Core的console app来完成这部分独立的功能。做Unity开发的时候也知道mono可以支持C#代码的跨平台运行,在此打算把C#生态涉及到的各种概念梳理一下。包括C#、.Net、.Net Framework、.NetCore、.Net Standard、mono、MAUI、WPF、Telerik、CIL、CLR、ECMA标准等等。

最初C#是微软推出的基于.Net Framewok的编程语言。C#与Java一样是托管语言,通过编译器生成中间语言 CIL( Common Intermediate Language ),再在运行时由中间语言运行时库CLR( Common Language Runtime)翻译执行并调用对应系统的API来工作。因为C#语法比较接近C/C++,但具有托管语言的优势(内存管理,异常机制等),很快流行起来。但当初的.Net Framework只支持Windows平台,就有公司及开源社区希望能让C#跨平台运行,这就是mono的出现。此后C#语言就不再是微软自家的产品了,需要有统一的标准。关于C#语言及C#编译出来的中间语言CIL的标准由欧洲计算机协会ECMA(European Computer Manufacturers Association)制定。

Continue reading

C++ 数据对齐 问题

上一篇文章提到了数据对齐问题,那我们就来看看C++数据对齐的规则,举例分析一下,最后看一个由数据对齐引起的BUG,并思考其带给我们的意义。

首先为什么要数据对齐?现代的64位计算机,总线位宽为64个比特(bit),即8个字节(byte),CPU的寄存器也是8个字节大小,所以访问内存也总是以8个字节为单位。如果一份不足8字节大小的数据因为布局问题跨越了两个8字节单位,这样要读这份数据的时候,就要通过两次总线传输,传递16字节的数据,CPU也要分级缓存这16字节的数据,这实在是太糟糕了。同理,对于32位的系统,小于4字节的数据就不应该夸两个4字节空间,还有其他的平台可能数据访问一次只有2字节甚至1字节。综合这些,数据对齐就是要求数据应该排放在其大小的自然边界上,简单说就是大小为N(1,2,4,8,16,32)的数据不应该放在两个N格子之间,而应该放在一个单独的N格子之内。

上面解释了为什么要数据对齐,要对齐的情况好像还挺多的,也挺复杂的。我们把编译器关于数据对齐的策略总结为三条规则。

规则一:成员变量根据自己的大小来对齐。

规则一的意思就是,关于结构体内该成员是否要对齐,对齐到什么位置,不是看上一个变量,也不是看下一个变量,而是看自己。定义一个int,就要对齐到sizeof(int)整数倍的位置,定义一个double,就要对齐到sizeof(double)整数倍的位置。

规则二:结构体大小必须是最大成员变量大小的整数倍。

规则二定义的是结构体数组最后补齐的情况,如果一个结构体中定义了一个int与一个double,那么最大成员变量是double,大小为8。这时结构体虽然只有4(int) + 8(double)= 12字节大小,但会补齐为8的整数倍 16。这样做是为了处理结构体数组时,每一个结构体内的每一个成员变量都处于边界上。

结合规则一与规则二,我们就可以处理简单结构体的数据对齐了,先来看个例子:

Continue reading

利用C++特性 从内部成员地址索引外部对象

标题很纠结,来看看实际需求。我们经常说的class A 包含 class B有两种形式,一种是继承,一种是组合。对于这两种情况,假设我们现在得到class B 的地址,怎么通过这个地址反向找到class A 的地址呢?

首先来看看组合的情况:

wp1

对于GetExternalData()函数而言,它只拿到了内部成员MyClassB的地址,但想通过它访问外部的MyClassA的数据要怎么做到呢?首先我们要对于MyClassA的内存布局有一个概念:

Continue reading