Linux 编程

目录

 

Linux 编程环境

vim 使用简介

GCC编译器

GDB 调试器

1.常用调试命令

2.调试多线程程序命令

3.使用 core dump 文件调试

Linux 网络编程

进程的产生

 


Linux 编程环境

vim 使用简介

1.普通模式下按下 I 键进入插入模式,再按下 Esc 键返回普通模式。

2.建立文件:“vim 文件名”

3.退出vim:普通模式下输入“: wq ” 保存并退出当前文件。“: q! ”操作可以实现不保存强制退出。

4.vim 编辑文本:

  • 移动光标 h、j、k、l
  • 删除字符 x、dd、:普通模式下 按下 x 删除单个字符;使用dd 命令删除一整行
  • 撤销与重做 u、Ctrl+R:使用 u 命令撤销可以取消之前的删除等操作;使用 Ctrl+R 作为重做命令(反撤销)
  •  复制粘贴 p、y:使用 yy 命令拷贝一整行

GCC编译器

1.使用“ g++ 文件名 ” 命令编译 cpp 文件,默认生成可执行文件 a.out 。“ ./a.out ”查看运行结果,./表示本目录下,不写则命令无效;如果希望生成指定的可执行文件名,使用选项 -o,例如“ g++ -o test hello.cpp ”。“ ./test ”查看运行结果。

2.多个文件编译:GCC 可以自动编译多个文件,不管是目标文件还是源文件,都可以使用同一个命令编译到一个可执行文件中。

  • “ g++ -o test string.cpp main.c ”将两个源文件中的程序编译成一个可执行文件,test
  • “ g++ -c string.cpp main.cpp ”先生成目标文件然后进行链接,“ g++ -o test string.o main.o” 生成 test

3.多文件工程的编译

  • 命令行:“ g++ -o cacu add/add_int.cpp sub/sub_int.cpp main.cpp” 将当前目录下的 main.cpp 与当前目录下文件夹 add 中的 add.cpp 和文件夹 sub 中的 sub.cpp 一同编译生成可执行文件 cacu
  • 多文件的 Makefile:Makefile 是进行程序编译时使用的编译配置文件,相当于提前将多条编译语句先写入一个 makefile 文件中

GDB 调试器

1.常用调试命令

1.编译可调式程序:要使用 GDB 进行调试,在编译程序的时候需要加入 -g 选项 “ g++ -o test string.cpp main.c -g ”,GCC会向程序中加入“楔子”,GDB 能够利用这些楔子与程序交互。

2.使用 GDB 调试程序:“ gdb 要调试的文件名 ”,此处文件名为可执行文件,如 test 、a.out

3.打印代码内容 list:简写“ l ”

4.设置断点 break:“ b 行数 ”;

  • break 行号:程序停止在设定的行之前
  • break 函数名称:程序停止在设定的函数之前
  • break 函数 if 条件:条件断点设置指令,如果条件为真,程序到达指定行或函数时停止 “ b 行号 if i==2 ”
  • 显示当前所设置的断点信息:“ info break ”
  • 删除断点:“ delete b 断点编号 ”
  • 清除所有断点:“ clean ” ;清除指定位置的断点:“ clean 行号 ”

5.运行程序“ run ”;

6.显示变量:“ display i ”:设置监测点每次代码运行至此停止时,会显示变量 i 的值

7.中断后继续运行:“ c ”

8.打印变量或者表达式的值使用 print 命令,简写为 p

  • 可以用 p 打印一个结构体中各个成员的值“ p 结构体变量名 ”
  • 可以使用 p 计算代码中定义的函数调用的返回值,例 “p sum(3) ”

9.查看变量类型:

  • “ whatis 变量名 ”
  • “ ptype 变量名 ” 可以查看结构体变量的详细定义

10.单步调试:

  • 单步跟踪 next 命令:简写“ n ”
  • 进入函数体 step 命令:简写“ s ”
  • 退出并返回调用的函数 finish 命令:如果已经进入某个调用的函数,想退出函数的运行,返回到调用的函数中

11.调用路径 backtrace:简写“ bt ”,打印函数的调用路径,生成一个顺序列表,显示函数从最近到最远的调用过程,同时会显示调用函数的传入参数

12.多线程 thread:多线程由于执行过程中的调度随机性,所以调试时要

  • 获得线程的 ID 号
  • 然后转到该线程进行调试

调试完程序后使用 q 命令退出。

2.调试多线程程序命令

2.1 多线程调试,最重要的几个命令:

info threads                        查看当前进程的线程。
                                          GDB会为每个线程分配一个ID, 后面操作线程的时候会用到这个ID.
                                          前面有*的是当前调试的线程.

thread <ID>                      切换调试的线程为指定ID的线程。

break file.c:100 thread all    在file.c文件第100行处为所有经过这里的线程设置断点。

set scheduler-locking off|on|step    
      在使用step或者continue命令调试当前被调试线程的时候,其他线程也是同时执行的,
      怎么只让被调试程序执行呢?
      通过这个命令就可以实现这个需求。
         off      不锁定任何线程,也就是所有线程都执行,这是默认值。
         on       只有当前被调试程序会执行。
         step     在单步的时候,除了next过一个函数的情况
                  (熟悉情况的人可能知道,这其实是一个设置断点然后continue的行为)以外,
                  只有当前线程会执行。

thread apply ID1 ID2 command        让一个或者多个线程执行GDB命令command
thread apply all command            让所有被调试线程执行GDB命令command。

2.2.使用示例:

线程产生通知:在产生新的线程时, gdb会给出提示信息
(gdb) r
Starting program: /root/thread 
[New Thread 1073951360 (LWP 12900)] 
[New Thread 1082342592 (LWP 12907)]---以下三个为新产生的线程
[New Thread 1090731072 (LWP 12908)]
[New Thread 1099119552 (LWP 12909)]

查看线程:使用info threads可以查看运行的线程
(gdb) info threads
  4 Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
  3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
  2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)

注意,行首为gdb分配的线程ID号,对线程进行切换时,使用该ID号码
另外,行首的星号标识了当前活动的线程
切换线程:
使用 thread THREADNUMBER 进行切换,THREADNUMBER 为上文提到的线程ID号。
下例显示将活动线程从 1 切换至 4。
(gdb) info threads
   4 Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
   3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
   2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
* 1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb) thread 4
[Switching to thread 4 (Thread 1099119552 (LWP 12940))]#0   0xffffe002 in ?? ()
(gdb) info threads
* 4 Thread 1099119552 (LWP 12940)   0xffffe002 in ?? ()
   3 Thread 1090731072 (LWP 12939)   0xffffe002 in ?? ()
   2 Thread 1082342592 (LWP 12938)   0xffffe002 in ?? ()
   1 Thread 1073951360 (LWP 12931)   main (argc=1, argv=0xbfffda04) at thread.c:21
(gdb)
以上即为使用gdb提供的对多线程进行调试的一些基本命令。
另外,gdb也提供对线程的断点设置以及对指定或所有线程发布命令的命令

3.使用 core dump 文件调试

ulimit -c                                      查看默认是否生成 coredump 文件 若为 0 则默认不产生core dump

ulimit –c unlimited                    打开生成 core dump

gdb ./a.out core.1025                用 gdb 打开 core 文件

gdb 中会打印出了出问题的代码行如 result = a/b,并给出可能的出错原因。如:“segment fault” 或 “Program terminated with signal 8, Arithmetic exception”表示应用程序是因为接收到Linux内核发出的Signal 8信号量而终止执行,Signal 8是SIGFPE,即浮点数异常。

通过 bt 可以打印函数调用栈,辅助分析出错原因。

4.Linux 下内存泄漏检测

如果编译后 gcc 提示 warning 可能有内存泄漏,

使用内存检测工具 valgrind,valgrind --leak-check = full  ./a.out

打印出的 heap summary 信息中:

==6118== 100 bytes in 1 blocks are definitely lost in loss record 1 of 1 
==6118==    at 0x4024F20: malloc (vg_replace_malloc.c:236) 
==6118==    by 0x8048724: GetMemory(char*, int) (in /home/netsky/workspace/a.out) 
==6118==    by 0x804874E: main (in /home/netsky/workspace/a.out)

是在main中调用了GetMemory导致的内存泄漏,GetMemory中是调用了malloc导致泄漏了100字节的内存。基本可以定位错误。

打印出的 leak summary 信息统计了所有的内存泄漏。

 

Linux 网络编程

进程的产生

1.使用 getpid() 函数返回当前进程的 ID 号,getppid() 返回当前进程的父进程的 ID 号,原型如下,pid_t 是一个 tydef 类型,定义为 unsigned int

#include<sys/types.h>
#include<unistd.h>
pid_t getpid(void);
pid_t getppid(void);

2.进程复制 fork():以父进程为蓝本复制一个进程,返回进程 ID,失败返回 -1。特点是执行一次,返回两次,在父进程中返回的是子进程 ID 号,子进程中返回 0 。

#include<sys/types.h>
#include<unistd.h>
pid_t fork(void);

3.system() 调用 shell 外部命令在当前进程中开始另一个进程,成功时返回进程状态值。

#include<stdlib.h>
#include<stdio.h>
int main()
{
    int ret;

    printf("系统分配的进程号是:%d\n", getpid());
    ret = system("ping www.baidu.com -c 2");
    printf("返回值为:%d\n", ret);
    return 0;
}

4.进程执行 exec() 函数系列:使用 fork() 和 system() 的时候,系统都会建立一个新的进程,而原来的进程还会存在,直到用户显示的退出;而 exec() 函数会用新进程代替原有的进程,系统从新的进程运行,新进程的 PID 会与原来进程的 PID 值相同。

5.所有用户态进程的 初始进程 init :init 进程是所有进程的祖先,其他的进程都是由 init 进程直接或者间接 fork() 出来的

  • linux 下可使用命令 pstree 来查看系统中运行的进程之间的关系

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值