Linux day2 笔记
.

1. 使用vs_code编写C/C++程序

下载安装之后,就可以找到这个程序
image.png

1.1 关于vscode的插件

vscode是一个扩展性极强的一个文本编辑工具。
通过安装各种各样的插件,能够编写大多数流行语言的代码。
还有很多其他意想不到的功能。
image.png
我们安装的插件
C/C++编辑的插件
image.png
简体中文的插件
image.png
image.png

1.2 编译和调试程序

image.png
编写代码之后配置
image.png
image.png
选中之后,会出现一个tasks.json 是一个编译工程的配置
image.png

  1. {
  2. // 有关 tasks.json 格式的文档,请参见
  3. // https://go.microsoft.com/fwlink/?LinkId=733558
  4. "version": "2.0.0",// 版本
  5. "tasks": [ // 任务
  6. {
  7. "type": "shell", // 脚本类型
  8. "label": "build", // 任务名
  9. "command": "/usr/bin/gcc", // 编译命令
  10. "args": [ // 编译的参数 gcc -g file -o xxx -l pthread
  11. "-g",
  12. "${file}",// 文件名有可能出问题
  13. "-o",
  14. "${fileDirname}/${fileBasenameNoExtension}",
  15. "-l",
  16. "pthread"
  17. ],
  18. "options": {//编译时运行目录
  19. "cwd":"${workspaceFolder}"
  20. },
  21. "problemMatcher": [
  22. "$gcc"
  23. ]
  24. }
  25. ]
  26. }

如果需要调试
image.png

  1. {
  2. "version": "0.2.0",
  3. "configurations": [
  4. {
  5. "name": "(gdb) Launch", // 配置名称,将会在启动配置的下拉菜单中显示
  6. "type": "cppdbg", // 配置类型,这里只能为cppdbg
  7. "request": "launch", // 请求配置类型,可以为launch(启动)或attach(附加)
  8. "program": "${fileDirname}/${fileBasenameNoExtension}", // 将要进行调试的程序的路径 通常都会出问题
  9. "args": [], // 程序调试时传递给程序的命令行参数,一般设为空即可
  10. "stopAtEntry": false, // 设为true时程序将暂停在程序入口处,我一般设置为true
  11. "cwd": "${workspaceFolder}", // 调试程序时的工作目录
  12. "environment": [], // (环境变量)
  13. "externalConsole": true, // 调试时是否显示控制台窗口,一般设置为true显示控制台
  14. "internalConsoleOptions": "neverOpen", // 如果不设为neverOpen,调试时会跳到“调试控制台”选项卡,你应该不需要对gdb手动输命令吧?
  15. "MIMode": "gdb", // 指定连接的调试器,可以为gdb或lldb。但目前lldb在windows下没有预编译好的版本。
  16. "miDebuggerPath": "gdb", // 调试器路径,Windows下后缀不能省略,Linux下则去掉
  17. "preLaunchTask": "build" // 调试会话开始前执行的任务,一般为编译程序。与tasks.json的label相对应
  18. }
  19. ]
  20. }

编译C++程序,没有太大区别,选择g++就可以。
如果要想支持C++的特性,需要在编译选项中添加
-std=c++11
image.png

2. 关于gcc的编译

2.1 编译的4个步骤

编译分为4步:
预处理:
image.png
image.png
编译:可以将预处理之后的文件,翻译为汇编
image.png
image.png
汇编:将汇编指令翻译为机器指令,生成中间文件
image.png
链接:
image.png
=image.png

2.2 多文件编译

假如我们的程序是由多个.c文件构成的,这个是最为常见的需要。
每一个.c文件都需要单独编译为一个.o文件。
再使用gcc将所有的.o文件链接为一个可执行文件。

  1. main函数中的代码:
  2. #include <stdio.h>
  3. int Add(int a,int b);
  4. int g_nNum = 0;
  5. int main()
  6. {
  7. printf("Hello world");
  8. int m =10;
  9. int n =20;
  10. g_nNum = Add(m,n);
  11. printf("number is %d\n",g_nNum);
  12. return 0;
  13. }
  14. math中的代码
  15. int Add(int a,int b)
  16. {
  17. return a+b;
  18. }

image.png
image.png
多文件编译,如果需要每一个都单独编译为.o文件,再链接,手工操作是比较麻烦的。
可以使用 makefile的脚本,去编写编译规则,然后去编译。

3. 关于动态库和静态库

3.1 关于动态库的使用

在Linux平台,动态库的文件后缀是 .so文件。与之对应的在windows平台是.dll文件。
使用库的主要目的:将代码提供给别人用的同时,还能隐藏自己的代码。

  1. 构建一个 so文件出来,并编译到目标程序中

image.png

  1. 不能直接运行,需要将so文件放置在 usr/lib目录下。

3.2 关于静态库的使用
生成一个.o文件
image.png
将.o文件打包成一个静态库
image.png
将静态库添加到目标文件
直接就可以执行,因为代码已经被编译到目标程序中了。

4. 关于gdb调试的问题

源码调试:
n 单步步过
s 单步步入
c 直接运行程序
b 设置断点
start 启动程序
l 列出源码
r 重新开始
finish 结束当前函数
反汇编调试,有自己的一些命令
ni 单步步过
si 单步步入
b 设置断点 可以使用地址
c 直接运行 继续运行
反汇编的时候,可以使用peda插件。

  1. git clonehttps://github.com/longld/peda.git~/peda
  2. echo "source ~/GdbPlugins/peda/peda.py" > ~/.gdbinit

相对看起来好看一些。
image.png
我们还可以安装edb
https://github.com/eteran/edb-debugger.git
image.png

5. 文件操作

5.1 C的库函数和之前学习的是一样的

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <sys/stat.h>
  4. void testCreateFile() {
  5. // 1. create file
  6. FILE *fp=fopen("hello.txt","w+");
  7. if(fp==NULL){
  8. printf("fopen err");
  9. return;
  10. }
  11. // 2. write file
  12. char szBuf[100] = {"hello 15pb"};
  13. size_t size = fwrite(szBuf, strlen(szBuf),1,fp);
  14. if(size == 0){
  15. printf("fwrite err");
  16. fclose(fp);
  17. return;
  18. }
  19. // 3. close file
  20. fclose(fp);
  21. }
  22. void testReadFile() {
  23. // 1. create file
  24. FILE *fp=fopen("hello.txt","r+");
  25. if(fp==NULL){
  26. printf("fopen err");
  27. return;}
  28. // 2. get file size
  29. char szBuf[100] = {0};
  30. struct stat stcInfo = {0};
  31. stat("hello.txt",&stcInfo);
  32. int nSize = stcInfo.st_size;
  33. // 3. read file
  34. // fseek()
  35. size_t size = fread(szBuf, nSize,1,fp);
  36. if(size == 0){
  37. printf("fread err");fclose(fp);
  38. return;}
  39. // 3. close file
  40. fclose(fp);
  41. // 4. show info
  42. printf("read: %s\n", szBuf);
  43. }
  44. int main()
  45. {
  46. //testCreateFile() ;
  47. testReadFile();
  48. return 0;
  49. }
  50. 5.2 Linux的文件流操作
  51. #include <stdio.h>
  52. #include <string.h>
  53. #include <sys/stat.h>
  54. #include <fcntl.h>
  55. #include <unistd.h>
  56. void testCreateFile1() {
  57. // 1. create file
  58. int fd = open("hello1.txt",
  59. O_CREAT|O_WRONLY, //dakai de shuxing
  60. S_IRWXU | S_IRWXG | S_IRWXO//butong yonghu yonghuzu de caozuo
  61. );
  62. if(fd== -1){
  63. printf("open err");return;
  64. }
  65. // 2. write file
  66. char szBuf[100] = {"hello 15pb"};
  67. size_t size = write(fd, szBuf, strlen(szBuf));
  68. if(size == -1){
  69. printf("write err");close(fd);return;
  70. }
  71. // 3. close file
  72. close(fd);
  73. }
  74. void testReadFile1() {
  75. // 1. create file
  76. int fd = open("hello1.txt",O_CREAT|O_RDONLY);
  77. if(fd== -1)
  78. {
  79. printf("open err");
  80. return;
  81. }
  82. // 2. get file size
  83. char szBuf[100] = {0};
  84. struct stat stcInfo = {0};
  85. stat("hello1.txt",&stcInfo);
  86. int nSize = stcInfo.st_size;
  87. // 3. read file
  88. size_t size = read(fd, szBuf, nSize);
  89. if(size == -1)
  90. {
  91. printf("read err");
  92. close(fd);
  93. return;
  94. }
  95. // 3. close file
  96. close(fd);
  97. // 4. show info
  98. printf("read: %s\n", szBuf);
  99. }
  100. int main()
  101. {
  102. //testCreateFile1();
  103. testReadFile1();
  104. return 0;
  105. }
  106. 5.3 遍历目录
  107. #include <stdio.h>
  108. #include <dirent.h>
  109. #include <string.h>
  110. #include <sys/stat.h>
  111. #include <errno.h>
  112. void enumdir(const char * path)
  113. {
  114. //1 .打开目录
  115. //参数1: 要打开的目录
  116. //返回值:返回目录流,成功返回非零,失败返回NULL
  117. struct DIR* pdir = opendir(path);
  118. if (pdir == NULL)
  119. {
  120. printf("open dir %s error: %s\n", path, strerror(errno));
  121. return;
  122. }
  123. struct dirent * info;
  124. // 2.读取目录中子文件信息
  125. // 参数1 : 目录流结构体
  126. // 返回值 : 成功返回目录流下的结构体dirent信息,失败返回NULL
  127. while (info = readdir(pdir))
  128. {
  129. // 输出目录下的文件类型 (DT_DIR) 文件名称
  130. printf("[%d]:%s\n", info->d_type, info->d_name);
  131. };
  132. // 关闭目录流
  133. closedir(pdir);
  134. }
  135. int main()
  136. {
  137. enumdir("/home/pb");
  138. return 0;
  139. }