`
lovnet
  • 浏览: 6812910 次
  • 性别: Icon_minigender_1
  • 来自: 武汉
文章分类
社区版块
存档分类
最新评论

C++与C#对比学习:预编译与编译机制(一)

 
阅读更多

源代码的翻译简介

我们知道机器其实是比较笨的,它只认识0101这样的机器语言.你用高级语言写的源代码对机器来说就像地球人看火星文一样,没法整明白的.必须要经过中间很多翻译环节.通常来说分为如下四步,实际上每一步都相当于在做翻译中的一小部分工作.

1.预编译阶段,也叫预处理.顾名思义就是在处理之前预先做些准备工作.比如你写的#include #define这样的预编译指令,还有一些注释,编译器可不认识.你得先用个预处理器把它们翻译下,让编译器可以认识才行.比如把注释去掉.把#include这样的标志也去掉,替换成引用的头文件的实际内容.

2.编译阶段.经过预处理后的源码,编译器就做啥词法分析,语法分析,如果它觉得老兄你写的代码错的有点太离谱就给个error,如果觉得源码虽然不太规范,但还不是太不靠谱就只给个warning.经过分析没有error的话最终会被翻译成等价的汇编语言.

3.汇编阶段.把第2步产生的汇编代码再翻译成0101这样的机器语言.

4.链接阶段.可能你写的代码并不是编译汇编成某一个文件,可能分散在不同的文件中.所以需要把它们链接到一起.成了最终的可执行文件,你双击下就可以运行了.这一步最终产生一个成品,前面三步产生的只是半成品.

注意事项.实际上只是便于理解像上面这样划分.虽然有时确实严格按上面四步,每一步有相应的工具来做那些工作.但有时并没有严格像上面这样按4步,但大概思想差不多.

1.)比如像C#,它没有像C++一样有一个独立的预处理器来做预处理阶段的工作,而是由编译器一起做了.实际上我们可以把上面4步全部用一个工具(编译器)做了,而不用分成4步然后用4个工具来做

2.)实际上严格来说,第4步产生了可执行文件,变成了机器能识别的机器语言就真的意味着机器能认识了.这时的可执行文件还是要基于操作系统的,只有依托于操作系统才能运行.实际上你可这样想,操作系统把底层硬件做了一个抽象.操作系统与底层硬件一起组成了一个抽象的"机器",你最终的代码能被这个"机器"识别

3.)实际上你还可以在操作系统上面再抽象一层,抽象出一个"机器",比如C#最终翻译成MSIL(微软中间语言),也是二进制串,但真正的机器可不认识.只有CLR这个"机器"能认识.另外像html标识语言,它翻译后也只有浏览器这个"机器"可以认识

不过为了便于理解,我们还是按上面说的4个步骤来分析下每一步具体做了些啥工作.先来说第一步预编译

预编译(或者说预处理)

预编译能做的事主要是下面4项

1.通过#include从其他文件里复制源程序正文来替换.我们在C++经常用它来引用头文件啊

2.通过#define定义宏,可以简单的把宏理解为把一长串字符ABC用一个很短的字符A来在代码中代替.然后预编译时又把所有的A替换回去,变成ABC.

3.条件编译,通过#define和#ifdef配合使用,把代码中不符合条件的代码块在预编译阶段全部删除掉.

4.用#progma以某种与实现有关的方式影响编译过程.比如有些警告信息你看着不顺眼,就可以通过#progma让编译器不再显示那警告信息

#include是C++中特有的,头文件也是C++中的概念.而头文件和#include在C#中没有了.那你肯定会有点迷糊,头文件起啥作用的?为啥C#中会没有?

C++头文件作用,为什么C#不需要头文件.

C++头文件作用

C++中的头文件自然是有些好处,可以很清晰的通过看一个头文件而知道一个类里面有啥成员变量和成员函数.然后可以通过引用一个头文件来使用其他类中的public成员和函数.不过其实头文件跟我们用define定义宏一样,只是方便我们而出现的.在预编译阶段全部被替换成了头文件中的实际内容.所以编译器编译的时候根本不会知道有头文件这东东存在.只有一个个的CPP文件.

在C++中,假如有有类Arwen需要用到类ABC的信息,Arwen中有函数Fun(),那必须在Arwen中用#include "ABC.h" 这样来引用头文件, 然后预编译的时候把#include "ABC.h"这一串给去掉.替换成文件ABC.h中的实际内容.比如void Fun();这些信息啊.然后呢接下来就是编译了,编译器就看你用到ABC的信息时是不是与ABC的声明吻合.例如你用ABC.Fun();函数时编译器一看Fun函数在声明中有就OK,但如果用ABC.Test();一看声明中没有,于是报错.

class ABC

{

public: void Fun();

};

类Arwen没预编译之前是下面这样

#include "ABC.h"

class Arwen

{

void CallFun() { ABC abc; abc.Fun(); }

}

预编译之后

class ABC

{

public: void Fun();

};

class Arwen

{

void CallFun() { ABC abc; abc.Fun(); }

}

C#不需要头文件的原因

namespace MyZone

{

class ABC {public Fun() { } }

}

namespace MyZone

{

classArwen {

public CallFun() {ABC abc = new ABC(); abc.Fun(); }

}

}

假如在C#,然后有类Arwen,需要用到类ABC的信息.可C#没有头文件的概念,在Arwen中用到ABC时咋整啊? C#的原理是这样的,编译的时候是先生成一些元数据(metadata),元数据里面有名称空间信息,然后每个名称空间(namespace)下面有些啥类,类的访问限制,类中有些啥字段,方法等(字段与方法等同于C++中的成员变量和成员函数).有了这些信息后编译器就可以靠这些信息判断你调用其他类时是否正确.像上面Arwen与ABC都在命名空间MyZone下面.编译器检查abc.Fun()调用正确不,会去元数据中查找MyZone下面跟类ABC相关信息.

但如果ABC如类Arwen不在同一个namespace中的话就得在Arwen前面用using ABCnamceSpace; 引用一个命名空间.实际上这和C++中用#include引用头文件的思想有点类似.C#是用using 引用命名空间.因为默认情况下编译器只会去检查与当前类相同命名空间的所有类信息.只有你用using显式引用了其他命名空间时才会也去检查那些命名空间下的类信息.

一般情况下一个项目就对应一个dll,与C++中的dll不同,C#的dll包含的信息更多,所有元数据都在dll中.而一般一个项目中也只用到一个命名空间.当然我说的是一般,实际上一个dll中可以有多个命名空间, 或者多个dll是同一个命名空间. dll是实际存在的文件.命名空间是一个抽象的概念性的东西.
分享到:
评论

相关推荐

    C/C++和C#混合编程

    C#和C++在编译过程中的区别主要体现在它们的目标代码上:C#编译成微软中间语言(MSIL),而C++通常直接编译成本地机器码。这种差异导致了两者之间直接调用的困难,特别是当涉及到类和对象时更是如此。传统的...

    C++与C#应用:C++调用C#DLL 示例源码

    本示例探讨了如何在C++程序中调用C#编译的动态链接库(DLL)的功能,这对于那些需要利用C#特性但又不能完全放弃C++项目的开发者来说尤其重要。下面我们将深入讲解这个主题,首先理解C++和C#的基础,然后详细解释如何...

    C++调用C#类库

    C#是.NET框架的一部分,而C++则可以是传统的C++或使用Microsoft的C++/CLI(Common Language Infrastructure)版本,后者是为了与.NET框架兼容而设计的。在本例中,我们假设C++项目使用了C++/CLI作为桥接层来调用C#的...

    C++反射库--RTTR预编译包

    RTTR通过提供一种预编译的机制,使得C++开发者也能享受到类似于Java或C#等语言的反射功能,而无需破坏类的继承结构。 RTTR的工作原理主要基于元数据(metadata)和元对象(meta objects)。它允许你在编译时对类、...

    c++ 与c#的中文字符串传递演示demo

    首先,我们要明白C++和C#之间的互操作性主要依赖于.NET框架的P/Invoke(Platform Invoke)机制。 1. **C++ 编译为 DLL** C++编写的代码可以通过创建动态链接库(DLL)来供其他程序调用。DLL文件包含可重用的函数和...

    C++与C#的一些比较

    预处理器指令在C++中用于条件编译,而在C#中,这些功能更多地被编译器特性所取代,如`#if`、`#endif`等。C#不使用头文件,而是使用`using`指令来引用命名空间。 异常处理方面,C#的`try`-`catch`-`finally`结构比...

    c++与c#互调的例子

    P/Invoke允许C#代码调用非托管代码,如C++编译的DLL。为了实现这一点,需要在C#中定义与DLL函数匹配的委托类型,并使用`DllImport`属性标记该委托,指定DLL的路径和函数名。例如,如果C++ DLL有一个名为`AddNumbers`...

    C#调用C++编译的DLL

    因此,学习如何在C#中调用C++编译的DLL是非常实用的技能。 #### 二、托管与非托管代码的区别 - **托管代码**:指使用.NET框架编写的代码,由CLR(公共语言运行时)管理,提供了垃圾回收等自动内存管理功能,提高了...

    C++ C#混合编程

    另一种方式是使用PInvoke(Platform Invoke),它是.NET Framework提供的一种机制,让托管代码可以调用非托管(如C++编译的DLL)的函数。 2. **CLR(Common Language Runtime)**:.NET Framework的核心组件,它...

    C++转C#的自动工具

    标题中的"C++转C#的自动工具"是一个用于将C++源代码自动转换为C#源代码的程序。这样的工具通常被开发人员用来方便地在两种不同的编程语言之间迁移项目,尤其是在一个团队需要从C++迁移到C#,或者希望利用C#特有的...

    C++调用C#的DLL程序实现方法

    把C#编译成DLL或者Axtive控件,再由C调用!比如使用C++调用C#的DLL。 SwfDotNet是.net下输出flash的类库。SwfDotNet是C#编写的,作者的C#水平,真是令我佩服。这是个特别好的读写Swf文件的库。但是,我要用在C++项目...

    C#与C++混合编程.pdf

    C#与C++混合编程涉及到将两种不同类型的代码(托管代码与本地代码)进行交互式调用,这是一个在软件开发中常见的需求。C#(发音为“看井”)是一种由微软开发的高级编程语言,它是一种面向对象、类型安全的编程语言...

    C++代码转C#

    - 转换的挑战包括:C#的垃圾回收机制与C++的内存管理不同,C#的面向接口编程与C++的面向对象编程有所差异,以及C#的特性如属性、事件和委托在C++中的实现方式等。 4. **配置文件**: - `Demo C# to C++ Converter...

    使用Swig转换C++库到C#示例代码

    通过查看和运行这个测试应用程序,我们可以学习到如何在C#中创建实例、调用方法、传递参数以及处理返回值,这些都是C#与C++交互的关键点。 在实际操作中,首先,我们需要阅读`SWIGDocumentation.pdf`以理解Swig的...

    非托管C++调用C#的dll

    非托管C++是指使用传统的C++编译器编译的代码,它不能与C#代码集成,需要使用一些特殊的技术来调用C#编写的dll。 知识点3:CLR VIA C#的作用 CLR VIA C#是一种技术,它可以在非托管代码中手动启动CLR来加载应用...

    MessagePack在C++和C#间传输数据

    3. **C++与C#的数据类型映射**:理解C++和C#中数据类型的对应关系,如基本类型、自定义类和结构体,是正确实现数据交换的关键。 4. **网络通信基础**:无论是通过TCP/IP套接字还是其他通信协议,你需要知道如何在...

    C++和C#的却别与各自的用法

    C++的多继承特性允许一个类继承多个父类,而C#仅支持单一继承,但可以通过接口实现多态性。 2. 垃圾回收:C#内建垃圾回收机制,能够自动管理内存,避免内存泄漏。C++则需要程序员手动管理内存,提供了更多控制权但...

    Protobuf编译C++和C#文件,带例子

    标题中的"Protobuf编译C++和C#文件,带例子"指的是使用Protocol Buffers(简称Protobuf)这一数据序列化工具,为C++和C#编程语言编译定义的数据结构。Protocol Buffers是Google开发的一种高效、灵活且可扩展的数据...

    c++ to c#c++ to c#c++ to c#c++ to c#c++ to c#c++ to c#c++ to c#c++ to c#c++ to c#

    9. **编译和运行环境**:C++代码编译成可执行文件,而C#编译为中间语言(IL),在.NET环境中通过CLR(Common Language Runtime)运行。 10. **UI开发**:C++可以与WinAPI或Qt等库配合开发图形界面,C#则使用Windows...

    C++调用C#DLL的DEMO

    在这个DEMO中,可能包含了一个C++程序(如`c_net_test.cpp`)和一个C#编译后的DLL文件。C++代码会展示如何进行上述步骤,而C#代码则包含实际的功能实现。字符串转换是跨语言通信中常见的操作,C#可能提供了丰富的...

Global site tag (gtag.js) - Google Analytics