无论学习编程语言,开始入门的“Hello World”是必不可少的。
#include
using namespace std;
int main()
{
count<<"hello world"<<endl;
return 0;
}
看起来很简单,但是深究起来却有很大的学问。没错这其实是一位学长的腾讯面试题。是不是有点怀疑人生,其实面试官只是借助着一个简单的程序深挖了背后的底层原理。
先来看一个概念叫做命名空间。
#include
//命名空间
int scanf=0;//c不能用关键字作为变量名,但是函数没有规定,所以按理来说应该是可以的
int main()
{
printf("%d",scanf);
return 0;
}
但是却有这么一个错误。
我们知道在预处理的时候会展开头文件,scanf函数在里面,所以这里是有歧义,在我们写项目的时候会出现同样的问题,假如出现了同样的命名,在链接合成同一个文件的时候,那声明成static可以解决吗,static是解决一个全局变量在多个文件进行编译冲突问题,解决不了命名的这个问题,显然C语言对这个问题没有办法,Cpp通过命名空间来改变来解决这个问题。
#include
//命名空间,域
namespace bit
{
int scanf=0;
}
int main()
{
printf("%d",scanf);
return 0;
}
编译成功
输出竟然是这么大,为什么呢?
我们在代码里写的命名空间域还没有使用他,将它隔离起来,头文件展开的时候跳过,所以这里打印的是scanf的地址,严格来说应该打印%p,就打印了他的地址
namespace bit
{
int scanf=0;
}
他本质还是一个全局变量,要访问它有三种方法。
第一种是通过域作用限定符直接用。
printf("%d",bit::scanf);
第二种是单独展开特定的变量
namespace bit
{
int a=0;
int b=0;
int c=0
}
using bit::b;
int main()
{
printf("%d",b);
return 0;
}
第三种很粗暴,也就出现了文章开始的,我们经常用的那一种格式
namespace bit
{
int a=0;
int b=0;
int c=0
}
using namespace bit;
int main()
{
printf("%d",a);
printf("%d",b);
printf("%d",c);
return 0;
}
在写大型项目时,我们用第一种或者第二种进行展开。
在Cpp训练时,我们所需要所有的库便是在这个std中,通常选择全部展开。
using namespace std;
要使用cin(键盘),cout(控制台)。首先便是要包含头文件
include<iostream>
然后便是展开std命名空间,三种方式。
语法格式:
//可以认为字符串的东西流向cout
cout<<"hello";
//想要换行
cout<<"hello"<<endl;
自动识别内容,无需c语言一样指定格式
<< 和>>是运算符,cin和cout是对象
int i=0;
cin>>i;
当有不同类型变量的时候,用cin,cout
int main()
{
int i;
double d;
cin>>i>>d;
cout<<i<<d<<endl;
}
当这种情况,我们想要输出一些格式做一些说明,或者想让他有序一点,用printf更合适
struct Student
{
char name[10];
int age;
};
int main()
{
int i;
double d;
cin>>i>>d;
cout<<i<<d<<endl;
struct Student s={
"peter",18};
printf("name:%s age:%d\n",s.name,s.age);
}
先来看个概念
缺省:声明或定义的时候为函数的参数制定一个默认的值。
缺省还分为全缺省和半缺省
全缺省意思就是形参全部指定。
半缺省部分指定必需要从右向左给值。
缺省参数不能再函数声明和定义中同时出现。
就算缺省值一样也不行,必须在声明时给好
函数的一种特殊情况,Cpp允许在同一作用域种声明功能类似的同名函数,这些同名函数的形参列表
(参数个数或类型或顺序)必须不同。
假设当前有这么几个文件 test.h , test.cpp , main.cpp
经过这么几个过程
预处理:头文件展开,宏替换,条件编译
test.cpp->test.i main.cpp->main.i
编译:检查语法,生成汇编代码
test.i->test.s main.i->main.s
汇编把汇编代码转换成二进制机器码
test.s->test.o main.s->main.o
链接
-o形成可执行文件
汇编的时候通过call 函数地址,他不知道自己找的是什么(call_(?)),只能找到函数声明,
只有在链接时会在其他文件的符号表中通过函数名找,拿到地址。
windows查看底层原理太复杂,我们在Linux环境下查看。
先简单编一个c语言文件
通过objdump指令查看
我们可以看到c语言在调用时直接调用的函数名,多个相同的文件
再来看c++
查看obj文件
可以明显的看到c++与c语言的不同,c++使用了一个东西叫函数修饰规则。
通过_z[]+函数名+类型首字母,c++的重载函数只要参数不同修饰的名字就不同,这样链接的时候就会找到。
C语言没有修饰规则,所以直接通过名字去找,有同名就冲突了。