C++代码安卓代码没问题但是无法运行?

mingw-w64应该可以算是mingw的改进版本吧,mingw系列编译器是非常好的并且主流的c/c++编译器

mingw-w64只负责程序的编译,只提供命令行操作没有编辑代码的图像界面,代码的编写需要由文本编辑器(如vscode)来完成

但普通人群可能会因为一些原因下载失败,所以一般建议下载离线版解压后添加环境变量

下载后选一个合适的位置解压,这个位置也就相当于是安装位置(顺便给文件夹改个短一点的名字)

进入解压好的文件夹下的bin文件夹

然后在此电脑鼠标右键选择属性

选择系统环境变量下的Path

然后把刚刚复制的文件路径粘贴进去

出现下图的信息说明一切顺利

可以不要上面的 直接按照8266环境 这个就有了

破案1101起查缴财物6.9亿元!江苏打击整治养老诈骗专项行动战果显著

破案1101起查缴财物6.9亿元!江苏打击整治养老诈骗专项行动战果显著

不像python等动态语言,C、C++是静态语言,需要编译之后,然后才能执行,C++的编译器有很多,比如常见的MSVC、g++(gcc)、等,本文介绍g++,关于g++的详细介绍,本文不再介绍,可以查阅相关文档。

二、windows平台下g++的安装与配置

gcc原本是基于Linux平台的,但是在windows平台上提供了一个同样的实现,叫做MingW

但是有一个问题是,安装的过程中需要联网,即边下载边安装,这样很容易失败,所以一般是先下载离线文件,然后直接配置即可。

如果上面的下载速度很慢,也可以联系我,在我的网盘里面下载。下载下来是一个大约50M的压缩文件,解压该文件到相应的目录之下,比如我将其解压到D:\Program Files (x86)文件夹下,得到一个mingw64文件夹,会得到如下的一系列文件,如下:

解压之后就不需要在进行安装了,直接配置环境变量即可,关于如何配置环境变量,此处就不再赘述,给环境变量添加的路径为:

三、使用g++编译C++代码的四大过程

比如我有一个test.cpp的C++文件,代码如下:

1、预编译——宏的替换、注释消除

进入到代码test.cpp所在的文件夹,执行命令:

这时会生成一个后缀为.i的test.i的文件,这个文件里面进行了宏的替换,还有注释的消除等操作。

2、编译阶段——生成汇编语言

这个时候,会生成一个后缀为.s的文件,test.s,.s文件表示是汇编文件,用编辑器打开就都是汇编指令。

3、汇编阶段——生成机器代码

会生成一个后缀为.o的文件,test.o,.o是gcc生成的目标文件,用编辑器打开就都是二进制机器码。

4、链接——生成可执行程序

会生成一个后缀为.exe的文件,test.exe,即连接目标代码,生成可执行程序

四、C++代码运行过程的详解

C++为什么要进行预编译、预编译过程到底有什么作用呢?主要体现在以下几点:

比如#define m 5,那么在该阶段会将程序中的m全部替换成5

当然,我们还可以定义带有参数的宏,如下

当上面的代码被编译和执行时,它会产生下列结果:

C++ 提供了下表所示的一些预定义宏:

这会在程序编译时包含当前行号。
这会在程序编译时包含当前文件名。
这会包含一个形式为 month/day/year 的字符串,它表示把源文件转换为目标代码的日期。
这会包含一个形式为 hour:minute:second 的字符串,它表示程序被编译的时间。

让我们看看上述这些宏的实例:

当上面的代码被编译和执行时,它会产生下列结果:

一般情况下,程序的每一行源代码都是要编译的。特殊情况下,只有满足一定条件的程序才需要编译,这就是条件编译。常用的条件编译关键字主要有#if、#ifdef、#ifndef、#else、#elif和#endif,那有什么好处呢?用来有选择地对部分程序源代码进行编译,可以有选择性的进行编译,提高编译效率。

其功能是将被包含的文件中的源代码放进源文件中,从而实现代码重用。简单的来说就是相当于将#include后面的内容替换到当前的文件里面,这样既方便组织代码,又方便代码重用。

C语言中可以使用__FILE__表示本行语句所在源文件的文件名,使用__LINE__表示本行语句在源文件中的位置信息。#line指令可以重新设定这两个变量的值,其语法格式为

其中第二个参数文件名是可省略的,并且其指定的行号在实际的下一行语句才会发生作用。如下所示:

编译程序时,只要遇到 #error 就会跳出一个编译错误,既然是编译错误,要它干嘛呢?其目的就是保证程序是按照你所设想的那样进行编译的。
程序中往往有很多的预处理指令

当程序比较大时,往往有些宏定义是在外部指定的(如makefile),或是在系统头文件中指定的,当你不太确定当前是否定义了 XXX 时,就可以改成如下这样进行编译:

#pragma指令的参数有很多种形式,每种形式都代表了一种不同的功能,#pragma指令的参数的形式如下:

#pragma message指令使用于提示一些有用的信息,程序编译的过程中,在编译信息窗口输出这些信息。

#pragma argsused指令仅允许出现在函数定义之间,且仅影响下一个函数,使警告信息被禁止或者无效。

pragma startup指令可以实现设置程序启动之前需要执行的函数;pragma exit指令可以实现设置程序退出之前需要执行的函数。

#pragma warning可以实现设定提示信息的现实与否以及如何显示。简单示例如下:

功能:不显示4507和34号警告信息 功能:仅显示一次4385号信息 功能:将164号警告信息作为一个错误信息显示 功能:保存所有警告信息的现有警告状态 功能:从栈中弹出最后一个警告信息
  • 链接:链接程序的主要工作就是将有关的目标文件(库文件、.o文件)彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够被操作系统装入执行的统一整体。
  • 当链接器进行链接的时候,首先决定各个目标文件在最终可执行文件里的位置。然后访问所有目标文件的地址重定义表,对其中记录的地址进行重定向(加上一个偏移量,即该编译单元在可执行文件上的起始地址)。然后遍历所有目标文件的未解决符号表,并且在所有的导出符号表里查找匹配的符号,并在未解决符号表中所记录的位置上填写实现地址。最后把所有的目标文件的内容写在各自的位置上,再作一些另的工作,就生成一个可执行文件。
    • 静态链接:函数的代码将从其所在地静态链接库中被拷贝到最终的可执行程序中。这样该程序在被执行时这些代码将被装入到该进程的虚拟地址空间中。
    • 动态链接:函数的代码被放到称作是动态链接库或共享对象的某个目标文件中。链接程序此时所作的只是在最终的可执行程序中

      记录下共享对象的名字以及其它少量的登记信息。在此可执行文件被执行时,动态链接库的全部内容将被映射到运行时相应进程的虚地址空间。动态链接程序将根据可执行程序中记录的信息找到相应的函数代码。

注意:在编译过程中头文件不参与编译,预编译时进行各种替换以后,头文件就完成了其光荣使命,不再具有任何作用
最后以一张图来结束本次内容:

库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常

本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。

库有两种:静态库(.a、.lib)和动态库(.so、.dll)

所谓静态、动态是指链接。回顾一下,将一个程序编译成可执行程序的步骤:

之所以成为【静态库】,是因为在链接阶段,会将汇编生成的目标文件.o与引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

试想一下,静态库与汇编生成的目标文件一起链接为可执行文件,那么静态库必定跟.o文件格式相似。其实一个静态库可以简单看成是一组目标文件(.o/.obj文件)的集合,即很多目标文件经过压缩打包后形成的一个文件。静态库特点总结:

  • 静态库对函数库的链接是放在编译时期完成的。
  • 程序在运行时与函数库再无瓜葛,移植方便。
  • 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。

Linux下使用ar工具、Windows下visual studio使用lib.exe,将目标文件压缩到一起,并且对其进行编号和索引,以便于查找和检索。

通过上面的介绍发现静态库,容易使用和理解,也达到了代码复用的目的,那为什么还需要动态库呢?

为什么需要动态库,其实也是静态库的特点导致。

(1)空间浪费是静态库的一个问题。

(2)另一个问题是静态库对程序的更新、部署和发布页会带来麻烦。如果静态库liba.lib更新了,所以使用它的应用程序都需要重新编译、发布给用户(对于玩家来说,可能是一个很小的改动,却导致整个程序重新下载,全量更新)。

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行时才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可。

  • 动态库把对一些库函数的链接载入推迟到程序运行的时期。
  • 可以实现进程之间的资源共享。(因此动态库也称为共享库)
  • 将一些程序升级变得简单。
  • 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。

Window与Linux执行文件格式不同,在创建动态库的时候有一些差异。

在Windows系统下的执行文件格式是PE格式,动态库需要一个DllMain函数做出初始化的入口,通常在导出函数的声明时需要有_declspec(dllexport)关键字

Linux下gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要函数做特别的声明,编写比较方便。

与创建静态库不同的是,不需要打包工具(ar、lib.exe),直接使用编译器即可创建动态库。

关于如何在Linux和windows下面生成静态链接库和动态链接库以及如何在程序中使用它们,会在后面的文章里面进行叙述。

我要回帖

更多关于 安卓代码没问题但是无法运行 的文章

 

随机推荐