Linux day2 笔记
.
1. 使用vs_code编写C/C++程序
1.1 关于vscode的插件
vscode是一个扩展性极强的一个文本编辑工具。
通过安装各种各样的插件,能够编写大多数流行语言的代码。
还有很多其他意想不到的功能。
我们安装的插件
C/C++编辑的插件
简体中文的插件
1.2 编译和调试程序
编写代码之后配置
选中之后,会出现一个tasks.json 是一个编译工程的配置
{
// 有关 tasks.json 格式的文档,请参见
// https://go.microsoft.com/fwlink/?LinkId=733558
"version": "2.0.0",// 版本
"tasks": [ // 任务
{
"type": "shell", // 脚本类型
"label": "build", // 任务名
"command": "/usr/bin/gcc", // 编译命令
"args": [ // 编译的参数 gcc -g file -o xxx -l pthread
"-g",
"${file}",// 文件名有可能出问题
"-o",
"${fileDirname}/${fileBasenameNoExtension}",
"-l",
"pthread"
],
"options": {//编译时运行目录
"cwd":"${workspaceFolder}"
},
"problemMatcher": [
"$gcc"
]
}
]
}
如果需要调试
{
"version": "0.2.0",
"configurations": [
{
"name": "(gdb) Launch", // 配置名称,将会在启动配置的下拉菜单中显示
"type": "cppdbg", // 配置类型,这里只能为cppdbg
"request": "launch", // 请求配置类型,可以为launch(启动)或attach(附加)
"program": "${fileDirname}/${fileBasenameNoExtension}", // 将要进行调试的程序的路径 通常都会出问题
"args": [], // 程序调试时传递给程序的命令行参数,一般设为空即可
"stopAtEntry": false, // 设为true时程序将暂停在程序入口处,我一般设置为true
"cwd": "${workspaceFolder}", // 调试程序时的工作目录
"environment": [], // (环境变量)
"externalConsole": true, // 调试时是否显示控制台窗口,一般设置为true显示控制台
"internalConsoleOptions": "neverOpen", // 如果不设为neverOpen,调试时会跳到“调试控制台”选项卡,你应该不需要对gdb手动输命令吧?
"MIMode": "gdb", // 指定连接的调试器,可以为gdb或lldb。但目前lldb在windows下没有预编译好的版本。
"miDebuggerPath": "gdb", // 调试器路径,Windows下后缀不能省略,Linux下则去掉
"preLaunchTask": "build" // 调试会话开始前执行的任务,一般为编译程序。与tasks.json的label相对应
}
]
}
编译C++程序,没有太大区别,选择g++就可以。
如果要想支持C++的特性,需要在编译选项中添加
-std=c++11
2. 关于gcc的编译
2.1 编译的4个步骤
编译分为4步:
预处理:
编译:可以将预处理之后的文件,翻译为汇编
汇编:将汇编指令翻译为机器指令,生成中间文件
链接:
=
2.2 多文件编译
假如我们的程序是由多个.c文件构成的,这个是最为常见的需要。
每一个.c文件都需要单独编译为一个.o文件。
再使用gcc将所有的.o文件链接为一个可执行文件。
main函数中的代码:
#include <stdio.h>
int Add(int a,int b);
int g_nNum = 0;
int main()
{
printf("Hello world");
int m =10;
int n =20;
g_nNum = Add(m,n);
printf("number is %d\n",g_nNum);
return 0;
}
math中的代码
int Add(int a,int b)
{
return a+b;
}
多文件编译,如果需要每一个都单独编译为.o文件,再链接,手工操作是比较麻烦的。
可以使用 makefile的脚本,去编写编译规则,然后去编译。
3. 关于动态库和静态库
3.1 关于动态库的使用
在Linux平台,动态库的文件后缀是 .so文件。与之对应的在windows平台是.dll文件。
使用库的主要目的:将代码提供给别人用的同时,还能隐藏自己的代码。
- 构建一个 so文件出来,并编译到目标程序中
- 不能直接运行,需要将so文件放置在 usr/lib目录下。
3.2 关于静态库的使用
生成一个.o文件
将.o文件打包成一个静态库
将静态库添加到目标文件
直接就可以执行,因为代码已经被编译到目标程序中了。
4. 关于gdb调试的问题
源码调试:
n 单步步过
s 单步步入
c 直接运行程序
b 设置断点
start 启动程序
l 列出源码
r 重新开始
finish 结束当前函数
反汇编调试,有自己的一些命令
ni 单步步过
si 单步步入
b 设置断点 可以使用地址
c 直接运行 继续运行
反汇编的时候,可以使用peda插件。
git clonehttps://github.com/longld/peda.git~/peda
echo "source ~/GdbPlugins/peda/peda.py" > ~/.gdbinit
相对看起来好看一些。
我们还可以安装edb
https://github.com/eteran/edb-debugger.git
5. 文件操作
5.1 C的库函数和之前学习的是一样的
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
void testCreateFile() {
// 1. create file
FILE *fp=fopen("hello.txt","w+");
if(fp==NULL){
printf("fopen err");
return;
}
// 2. write file
char szBuf[100] = {"hello 15pb"};
size_t size = fwrite(szBuf, strlen(szBuf),1,fp);
if(size == 0){
printf("fwrite err");
fclose(fp);
return;
}
// 3. close file
fclose(fp);
}
void testReadFile() {
// 1. create file
FILE *fp=fopen("hello.txt","r+");
if(fp==NULL){
printf("fopen err");
return;}
// 2. get file size
char szBuf[100] = {0};
struct stat stcInfo = {0};
stat("hello.txt",&stcInfo);
int nSize = stcInfo.st_size;
// 3. read file
// fseek()
size_t size = fread(szBuf, nSize,1,fp);
if(size == 0){
printf("fread err");fclose(fp);
return;}
// 3. close file
fclose(fp);
// 4. show info
printf("read: %s\n", szBuf);
}
int main()
{
//testCreateFile() ;
testReadFile();
return 0;
}
5.2 Linux的文件流操作
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
void testCreateFile1() {
// 1. create file
int fd = open("hello1.txt",
O_CREAT|O_WRONLY, //dakai de shuxing
S_IRWXU | S_IRWXG | S_IRWXO//butong yonghu yonghuzu de caozuo
);
if(fd== -1){
printf("open err");return;
}
// 2. write file
char szBuf[100] = {"hello 15pb"};
size_t size = write(fd, szBuf, strlen(szBuf));
if(size == -1){
printf("write err");close(fd);return;
}
// 3. close file
close(fd);
}
void testReadFile1() {
// 1. create file
int fd = open("hello1.txt",O_CREAT|O_RDONLY);
if(fd== -1)
{
printf("open err");
return;
}
// 2. get file size
char szBuf[100] = {0};
struct stat stcInfo = {0};
stat("hello1.txt",&stcInfo);
int nSize = stcInfo.st_size;
// 3. read file
size_t size = read(fd, szBuf, nSize);
if(size == -1)
{
printf("read err");
close(fd);
return;
}
// 3. close file
close(fd);
// 4. show info
printf("read: %s\n", szBuf);
}
int main()
{
//testCreateFile1();
testReadFile1();
return 0;
}
5.3 遍历目录
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <errno.h>
void enumdir(const char * path)
{
//1 .打开目录
//参数1: 要打开的目录
//返回值:返回目录流,成功返回非零,失败返回NULL
struct DIR* pdir = opendir(path);
if (pdir == NULL)
{
printf("open dir %s error: %s\n", path, strerror(errno));
return;
}
struct dirent * info;
// 2.读取目录中子文件信息
// 参数1 : 目录流结构体
// 返回值 : 成功返回目录流下的结构体dirent信息,失败返回NULL
while (info = readdir(pdir))
{
// 输出目录下的文件类型 (DT_DIR) 文件名称
printf("[%d]:%s\n", info->d_type, info->d_name);
};
// 关闭目录流
closedir(pdir);
}
int main()
{
enumdir("/home/pb");
return 0;
}