【深蓝C++】【第2章】【知识点汇总】
0 前言
- 环境是ubuntu18.06
- IDE是clion
1 知识点汇总
1.1查看main函数返回的值
终端执行:
echo $?
如下:
- 操作系统会掉哟main,那么main的返回值就给操作系统
bupo@bupo-vpc:~/shenlan/C++/cap2/cmake-build-debug$ ./helloworld
Hello, World!
bupo@bupo-vpc:~/shenlan/C++/cap2/cmake-build-debug$ echo $?
0
- 返回 0 代表程序运行成功
- main函数返回值即使不是void类型。如果没有写返回语句,那么默认返回一个 0
- main函数的返回类型一定是int
1.2 头文件<>和“”区别
- 使用
“”
,系统会从当前的目录开始来寻找头文件 - 使用
<>
,系统从环境变量开始寻找 - 通常来讲,头文件属于自己编写的,属于当前工程的,会用
””
- 使用C++标准库的头文件,使用
<>
,且其头文件没有.h/.hpp等类型的后缀
1.3 输入cin和输出cout、cerr、clog的使用
- isotream:标准库提供的IO接口,用于与用户交互
- 输入流:cin;输出流:cout/cerr/clog
- 输出流的区别:1、输出目标;2、是否立即刷新缓冲区
- 缓冲区与缓冲区刷新:std:flush;std:endl;
1.3.1 cout、cerr、clog
- 将cout和cerr的信息存储起来
代码如下:
#include <iostream>
int main() {
std::cout << "out from cout";
std::cerr << "out from cerr";
}
编译并运行该代码输出:
out from coutout from cerr
则下面可以将其结果分别重定向到不同的文件中:
bupo@bupo-vpc:~/shenlan/C++/cap2/cmake-build-debug$ ./helloworld >txt1 2>txt2
bupo@bupo-vpc:~/shenlan/C++/cap2/cmake-build-debug$ cat ./txt1
out from coutbupo@bupo-vpc:~/shenlan/C++/cap2/cmake-build-debug$ cat ./txt2
out from cerrbupo@bupo-vpc:~/shenlan/C++/cap2/cmake-build-debug$
- cout是程序系统的输出
- cerr是一些错误的信息
- clog和cerr基本上相似,下面看一个程序:
#include <iostream>
int main() {
std::cout << "out from cout";
std::cerr << "out from cerr";
std::clog << "out from clog";
}
输出为:
out from coutout from cerrout from clog
然后同样重定位到不同的文件:
bupo@bupo-vpc:~/shenlan/C++/cap2/cmake-build-debug$ ./helloworld >txt1 2>txt2
bupo@bupo-vpc:~/shenlan/C++/cap2/cmake-build-debug$ cat ./txt1
out from coutbupo@bupo-vpc:~/shenlan/C++/cap2/cmake-build-debug$ cat ./txt2
out from cerrout from clog
- cerr和clog的区别在于是否立即刷新缓冲区,cerr立即刷新,clog日志信息不是立即刷新,缓冲区满了才会自动输出
1.3.2 刷新缓冲区 std::flush、std::endl
- flush是刷新缓冲区,将缓冲区中的信息显示
- endl是刷新缓冲区并且换行
- 刷新缓冲区会影响程序的执行速度,大量的使用刷新缓冲区不是一个很好的行为
1.4 名词空间namespace
1.4.1 自定义名字空间基本使用方式
- 名字空间:用于防止名称冲突
- 访问名字空间中元素的3种方式:域解析符::;using语句;名字空间别名
#include <iostream>
namespace Namespace1
{
void fun()
{ }
}
namespace Namespace2
{
void fun()
{ }
}
int main() {
//way 1
Namespace1::fun();
//way 2
//可以写在函数体外,但是不推荐
//因为本身使用命名空间就是为了防止冲突
using namespace Namespace2;
fun();
//way 3
namespace ns1 = Namespace1;
ns1::fun();
}
- 使用方式2的时候应该注意:命名空间声明可以写在函数体外,但是不推荐,因为本身使用命名空间就是为了防止名词冲突;
- 在cpp文件这样还好,如果在头文件这样写非常危险,因为如果引入这样写的一个头文件的源文件,都会有名词冲突的危险
- 最安全的写法就是使用方式1或者方式3
1.4.2 std名字空间
- C++标准库所定义的名字空间
1.5 查看C++文件生成的.o文件所有的外部链接及反向操作
- 名字空间和名称改编(name mangling)
1.5.1 name mangling
linux下的命令:
nm ./main.cpp.o
如下展示了main.cpp包含的所有外部链接:
bupo@bupo-vpc:~/shenlan/C++/cap2/cmake-build-debug/CMakeFiles/helloworld.dir$ nm ./main.cpp.o
U __cxa_atexit
U __dso_handle
U _GLOBAL_OFFSET_TABLE_
000000000000009b t _GLOBAL__sub_I__ZN10Namespace13funEv
000000000000000e T main
0000000000000052 t _Z41__static_initialization_and_destruction_0ii
0000000000000000 T _ZN10Namespace13funEv
0000000000000007 T _ZN10Namespace23funEv
U _ZNSt8ios_base4InitC1Ev
U _ZNSt8ios_base4InitD1Ev
U _ZSt4cerr
U _ZSt4clog
U _ZSt4cout
0000000000000000 r _ZStL19piecewise_construct
0000000000000000 b _ZStL8__ioinit
U _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
其中
0000000000000000 T _ZN10Namespace13funEv
0000000000000007 T _ZN10Namespace23funEv
就是链接的自己所写的名字空间的fun文件
1.5.1 de name mangling
- linux下命令
nm ./main.cpp.o | c++filt -t
如下:
bupo@bupo-vpc:~/shenlan/C++/cap2/cmake-build-debug/CMakeFiles/helloworld.dir$ nm ./main.cpp.o | c++filt -t
U __cxa_atexit
U __dso_handle
U _GLOBAL_OFFSET_TABLE_
000000000000009b unsigned short _GLOBAL__sub_I__ZN10Namespace13funEv
000000000000000e T main
0000000000000052 unsigned short __static_initialization_and_destruction_0(int, int)
0000000000000000 T Namespace1::fun()
0000000000000007 T Namespace2::fun()
U std::ios_base::Init::Init()
U std::ios_base::Init::~Init()
U std::cerr
U std::clog
U std::cout
0000000000000000 r std::piecewise_construct
0000000000000000 bool std::__ioinit
U std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*)
- 两者不会改变main,之所以改编是因为名称可能会和程序当中其他的名称相冲突(函数重载),main是唯一的,不可能同名,所以不会对其进行改变
1.6 系统I/O
- C/C++系统I/O比较
#include <iostream>
#include <cstdio>
int main()
{
std::cout << "Hello World" << std::endl;
printf("Hello World\n");
}
- printf:使用直观,但容易出错
- cout:不容易出错,但书写冗长
- C++20格式化库:新的解决方案
#include <iostream>
#include <cstdio>
int main()
{
int x = 10;
std::cout << "I have " << x << " pens\n";
printf("I have %d pens\n", x);
}
1.7 ==使用的技巧,if和while循环
- 可以将常量放在==左边以防止误用 ,可以在常量再加上一个const
如下:
#include <iostream>
int main()
{
const int x = 42;
std::cout << "Please input a number: \n";
int y = 0;
std::cin >> y;
if(x == y)
{
std::cout << "You are right!\n";
}
else
{
std::cout << "You are wrong!\n";
}
}
- 使用while循环,用于循环执行
#include <iostream>
int main()
{
const int x = 42;
int y = 0;
while(x != y)
{
std::cout << "Please input a number: \n";
std::cin >> y;
}
std::cout << "You are right!\n";
}
1.8 结构体与自定义数据类型
- 结构体:将相关的数据放置在一起
- 可以通过点操作符(.)访问内部元素
- 可以作为函数的输入参数或返回类型
- 可以引入成员函数,更好地表示函数与数据的相关性
#include <iostream>
struct Point
{
int x;
int y;
void IncX()
{
x = x + 1;
}
};
Point& fun(Point &p)
{
p.x = p.x +1;
return p;
}
int main()
{
Point p;
p.x = 3;
p.y = 4;
fun(p);
std::cout << p.x << " " << p.y << '\n';
p.IncX();
std::cout << p.x << " " << p.y << '\n';
}