一、Hello World!
#include<iostream> //预处理命令,寻找iostream这个文件,将该文件中的所有内容都复制粘贴到目前这个文件内
int main()
{
std::cout << "Hello World" << std::endl;
//等价于
cout.
std::cin.get();
}
任何以 # 开头的都是预处理指令,预处理发生在“真正”的编译之前
运算符 其实 就是函数
IDE简介
左边:配置,一系列的规则用于如何编译一个项目
右边:解决方案,是我们目前编译的木匾平台。x86–win31
项目属性页,决定我们的文件被如何编译的规则
编译与链接
-
所有.cpp文件都会被编译,而头文件(head file)则不会。头文件是通过预处理器被include到cpp文件里
-
每个cpp文件会被编译成一个object文件,用Windows编译器扩展名是.obj
-
上图属性页里面可以看到链接器(linker),其作用就是把所有obj缝合成一个exe文件
-
在vs里,可以用CTRL + F7 单独编译一个cpp文件
-
错误信息只看 输出窗口 ,错误列表不全面
编译
大致流程:
1、pre-process(预处理)代码,也就是所有的预处理语句会在那时被评估
2、预处理之后,进入tokenizing(标记解释)和parsing(解析)阶段,基本就是把这些C++文本处理成编译器能读和处理的语言。基本结果就是创建某种叫做abstract syntax tree(抽象语法树)的东西,也就是我们代码的表达,但是是以抽象语法树的形式
3、开始产生真正的CPU会执行的机器码
让编译器输出一个文档,里面包含所有这些预处理评估的结果(测试完之后关闭,因为不会生成 .obj文件了):
打开该选项后,编译cpp文件之后,会生成.i文件,即预处理后的文件:
现在,来看一下.obj里面是什么内容,直接查看会看到机器码,现在修改一下项目属性:
这样编译后会生成一个.asm文件,此时用文本编辑器打开它,这基本就是刚刚那个obj文件所含内容的一个可读版本(也就是汇编语言)
这里会发现会有很多额外的东西,这是因为我们是在debug环境下编译的,而debug是不会做任何优化的,而且会有很多额外的东西,以确保我们的代码尽可能冗长以利于debug。所以现在,回到属性页面:
此时如果直接编译,会报错,因为O2和RTC不兼容,故继续修改:
此时再编译可以成功,然后再次查看汇编文件,会发现小了很多(因为之前编译器会插入一些代码来帮助我们debug,现在去掉了):
linker在联系各个cpp生成的obj文件是,会查找这个函数签名
- 当我们调用函数时,编译器就会生成一个call指令
总结 :
编译器会根据我们的源文件(source file)生成包含机器码和我们定义的常量数据的二进制文件(object file)
链接
- 链接的主要工作就是找到每个符号和函数的位置,并将它们链接到一起。
- 每一个exe(可执行)文件,都必须有一个入口函数,不一定是main函数,只是必须有一个入口点。
- 如果链接器找不到一个一模一样的(如,函数名,函数参数,函数返回值),就会出现链接错误。
- 如果在不同cpp文件中出现了一模一样的(函数),则可以通过编译,但无法通过链接,因为链接器不知道该链接到那个(函数)。
总结:
到头来链接器就是在编译之后,将编译过程中生成的所有对象文件链接起来,它还会导入我们可能用到的其他库(如C++标准库)。
一般项目:在头文件中声明函数,cpp文件中定义函数,其他cpp中include此头文件即可。
声明与定义
- 声明说明这个函数存在,编译器会无条件相信你
- 定义则是说这个函数到底是什么,这是这个函数的主体
//Log.cpp
#include<iostream>
void Log(const char* message)
{
std::cout << message << std::endl;
}
//main.cpp
#include<iostream>
void Log(const char* message);
int main()
{
Log("Hello World!");
/*如果只是编译这一个文件,编译器如何知道有一个Log函数在别的文件里呢?
回答是,它不知道。但如何正确运行代码呢?
这时就需要链接器(linker)了,当我们的文件被编译完毕之后,linker会去找Log的定义
然后跟我们main里面调用的函数联系起来,如果它没有找到该函数的定义,我们便会得到一个
linker error
*/
std::cin.get();
}
补充知识
错误查看相关:
- 当某函数被声明为static时,会意味着对着个函数的链接只发生在该文件内部
错误:
在链接时找不到相应的函数时会报这种错误
- 当某函数被声明为static时,会意味着对着个函数的链接只发生在该文件内部
- 当某函数被声明为inline时,会意味着在链接时只把函数的 身体拿过来取代调用