Akuaner

Akuaner 查看完整档案

西安编辑陕西科技大学  |  计算机科学与技术 编辑  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

Akuaner 发布了文章 · 3月23日

Linux - 文件操作 (库函数 & 系统调用)

文件

图片.png

图片.png

系统调用过程

图片.png

库函数和系统调用

图片.png

文件操作 -- 库函数

图片.png

文件操作 -- 系统调用

图片.png

fork()与文件

f_count 相当于一个计数器
f_count 当前有几个PCB连接着当前文件表
每当close();  f_count-1
只有当f_count == 0 时,才彻底释放
图片.png

查看原文

赞 0 收藏 0 评论 0

Akuaner 发布了文章 · 3月19日

Linux - 进程的创建fork()

main函数的参数

图片.png
argc 传进的参数个数
argv :参数
注意:利用for循环打印char* argv[]
  for循环内部不能直接定义int i=0; 内置不对

[root@localhost 2020-03-19]# ls
main  main.c
[root@localhost  2020-03-19]# ./main
argc:1
argc[0]=./main  

[root@localhost  2020-03-19]# ./main hello world
argc:3
argc[0]=./main  
argc[1]=hello  
argc[2]=world  

[root@localhost  2020-03-19]# ./main "hello world"
argc:2
argc[0]=./main  
argc[1]=hello world  

输出缓冲区

缓冲区 加载 停止条件  /\n
当遇到n的时候,才把缓冲区的内容全部输出
图片.png
注意:exit(0) 与_exit(0)的区别 :
  _exit(0)  不会去刷新缓冲区,直接结束进程

进程创建fork()⭐

图片.png

fork()后,会生成一个独立的子进程,父进程fork()后会返回子进程的pid,子进程会返回0
(子进程与父进程的pid !=)

    pid_t pid = fork();

创建(复制)的子进程会跳过创建他的fork(),避免进入死循环

图片.png

父子进程之间的联系

寻找与记录
PCB里面有单独的一部分 去记录 当前节点的父进程ppid是谁,我们很容易通过子进程去寻找父进程;
所以可以通过tid_t getppid(); 通过子id得到父id

但是我们应该怎么去寻找父进程的子进程呢?

所以在子进程返回给父进程过程中  记录下儿子的pid
便于以后去查找自己的儿子
仅此一次机会记录下来
指定哪个进程执行

子进程和父进程是两个进程
先执行谁取决于操作系统的调度算法 -并发执行

如果指明想要父子进程两个进程之间谁去允许 运行
可以利用:父进程会返回子进程pid 子进程返回0这一特性
使用这样的

if(pis==0) ..子进程.. else ..父进程..

fork()练习

例题一

注意事项:第二次循环的时候父子进程都进行了fork复制,所以有3个A3个B
图片.png

例题二

去掉n以后
缓冲区本来有的值也赋值了
AB | i=1
AB  AB |i=2
+AB |i=1
所以会出现4个A 4个B

    for(i=0;i<2;++i)
    {
        pit_t pid = fork();
        assert(-1 != pid);
        if(pid == 0)
        {
            printf("A ");
        }
        else
        {
            printf("B ");
        }
     } 
例题三

所以是3个A
图片.png

fork与内存

图片.png
图片.png
图片.png
引入写时拷贝技术:
图片.png

查看原文

赞 0 收藏 0 评论 0

Akuaner 发布了文章 · 3月19日

C++ Primer注解 - 迭代器(iterator)

迭代器

除了vector之外,还有好几种容器
但是只有string和vector常用下标访问
引入了用来代替下标访问 - 迭代器访问

string不属于容器,但是也可以使用迭代器

指针:取地址 ,指向地址
迭代器:返回成员 ,指向数据

begin运算符和end运算符

begin成员:负责返回首元素 迭代器
end成员:负责返回尾位置的下一位置元素 迭代器
如果容器为空,则begin和end返回的迭代器,都是尾后迭代器

注意点:begin()和end()返回的一定是个迭代器,要进行后续操作需要用一个迭代器变量把当前迭代器保留下来,再进行迭代器运算
图片.png

#include<bits/stdc++.h>
#include<vector>
#include<typeinfo>
using namespace std;
int main()
{    int array[]={10,20,30,40,50};
    int* pointer = array; //= &array[0]
    vector<int> A={10,20,30,40,50};
 
    cout<<"*pointer="<<*pointer<<endl;
    auto iter = A.begin(); 
    
    cout<<"vector.begin() ="<<(*iter); 
 } 
常见错误
// cout<<A.begin();<<endl; 初学者错误,迭代器返回的是迭代器
// (*A).begin(); 概念混淆,应该是对迭代器解引用,而不是对A数组解引用后再进行begin操作

迭代器运算

图片.png

迭代器指向下一元素经典错误:
// cout<<"vectoer second number ="<<*(iter++); 错误写法
必须是++iter !!!
#include<bits/stdc++.h>
#include<vector>
#include<typeinfo>
using namespace std;
int main()
{    
    vector<int> A={10,20,30,40,50};
    auto iter = A.begin(); 
    cout<<"vector first number="<<*iter<<endl; 
    cout<<"vector second number ="<<*(++iter); 
 } 
查看原文

赞 0 收藏 0 评论 0

Akuaner 发布了文章 · 3月16日

操作系统 - 操作系统基本知识

进程的概念

进程:正在执行的程序

创建进程: 先申请PCB -> 生成进程实体
结束进程:结束进程实体 -> 释放PCB
图片.png

僵尸进程

僵尸进程多了还是挺占内存的,只剩PCB 没进程实体
图片.png

孤儿进程

INIT跟个孤儿院一样
图片.png

进程状态的切换

https://blog.csdn.net/AKUANer...
图片.png

并行与并发

图片.png

内存管理- 简单分页

把一个程序分成若干小块,根据页表 找到对应的页帧中
https://blog.csdn.net/AKUANer...
图片.png
程序执行过程中,当所有页帧都满了,但是部分页帧迟迟用不到,会交换到外存当中去,引入了内存交换技术

逻辑地址

因为每次程序进入页帧不一定是同一个地方,所以物理地址不是一样的,通常采用逻辑地址
图片.png

虚拟内存

基于内存交换技术的虚拟内存技术,
我的理解:只要我交换的速度够快,赶得上我读取的速度,那么其实我的虚拟地址就是无穷大的,实际上做题计算的话,都是计算的单词最大虚拟内存
图片.png

操作系统发展史

一次放一个,用完了再拿下一个
一次性放五六个排排着,一次性用一个,全部用完了再一次拿五六个
时间片,每个程序读一小段,并发执行,只要切换的够快,就可以类似于并行
分时系统:真正的引入了时间片的概念 对于多道程序设计的完善
图片.png

查看原文

赞 0 收藏 0 评论 0

Akuaner 发布了文章 · 3月15日

Linux - 文件系统的认知 & 链接文件

文件系统

图片.png
windows默认NTFS系统
Linux默认EXT系统
U盘默认FAT32系统

索引式文件系统(indexed allocation)

inode里记录了所有block号码
图片.png

链表式文件存储系统

(非官方名)
常用于FAT文件系统中
必须从上一个block中才能知道下一个block在哪
图片.png

链接文件

图片.png

ls -i 查看inode结点号
ls -l 查看详细信息

软连接

软连接类似于 windows下的快捷键
结点号不同 , 指向源文件

ln -s 源文件 链接文件
[root@localhost 2020-03-15]# vim main.c
[root@localhost 2020-03-15]# ln -s main.c rlink.c
[root@localhost 2020-03-15]# ls -i
655407 main.c  655408 rlink.c
[root@localhost 2020-03-15]# ls -l
total 4
-rw-r--r-- 1 root root 63 Mar 15 17:13 main.c
lrwxrwxrwx 1 root root  6 Mar 15 17:14 rlink.c -> main.c
[root@localhost 2020-03-15]# cat rlink.c 
#include <stdio.h>
int main(){
    printf("hello~");
    return 0;
}
[root@localhost 2020-03-15]# cat main.c 
#include <stdio.h>
int main(){
    printf("hello~");
    return 0;
}

默认在link.c文件的当前目录下寻找main.c
图片.png

硬链接

结点号相同,类似于引用
只有同一结点号的所有文件被删除,这个文件才是真正的删除
一个结点号 - 多个文件

[root@localhost 2020-03-15]# ls
main.c  rlink.c
[root@localhost 2020-03-15]# ln main.c slink.c
[root@localhost 2020-03-15]# ls -i
655407 main.c  655408 rlink.c  655407 slink.c
[root@localhost 2020-03-15]# ls -l
total 0
-rw-r--r-- 2 root root 0 Mar 15 17:28 main.c
lrwxrwxrwx 1 root root 6 Mar 15 17:29 rlink.c -> main.c
-rw-r--r-- 2 root root 0 Mar 15 17:28 slink.c
[root@localhost 2020-03-15]# ln main.c slink2.c
[root@localhost 2020-03-15]# ls -l
total 0
-rw-r--r-- 3 root root 0 Mar 15 17:28 main.c
lrwxrwxrwx 1 root root 6 Mar 15 17:29 rlink.c -> main.c
-rw-r--r-- 3 root root 0 Mar 15 17:28 slink2.c
-rw-r--r-- 3 root root 0 Mar 15 17:28 slink.c
[root@localhost 2020-03-15]# rm slink2.c 
[root@localhost 2020-03-15]# ls -l
total 0
-rw-r--r-- 2 root root 0 Mar 15 17:28 main.c
lrwxrwxrwx 1 root root 6 Mar 15 17:29 rlink.c -> main.c
-rw-r--r-- 2 root root 0 Mar 15 17:28 slink.c
查看原文

赞 0 收藏 0 评论 0

Akuaner 发布了文章 · 3月13日

Linux - 进程管理 和用户管理

进程命令管理

进程:二进制加载到内存中,CPU执行期中指令整个过程
进程一定是运行中的程序
图片.png
PID 进程ID号

查看进程

ps :简略查看进程
top:动态查看进程
pstree:树状查看进程

图片.png

[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18501 pts/0    00:00:00 ps


[root@localhost 2020-3-13]# top
top - 17:55:23 up 108 days, 20:23,  1 user,  load average: 0.00,
Tasks:  64 total,   1 running,  63 sleeping,   0 stopped,   0 zo
%Cpu(s):  0.7 us,  0.3 sy,  0.0 ni, 99.0 id,  0.0 wa,  0.0 hi,  
KiB Mem :  1883496 total,   685784 free,    78456 used,  1119256
KiB Swap:        0 total,        0 free,        0 used.  1617020

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM 
29804 root      10 -10  125024  12516   9608 S  1.0  0.7 
  777 root      20   0  562388  16564   5876 S  0.3  0.9 
29730 root      10 -10   32612   4344   2780 S  0.3  0.2 
    1 root      20   0   51460   3680   2516 S  0.0  0.2 
    2 root      20   0       0      0      0 S  0.0  0.0 
    3 root      20   0       0      0      0 S  0.0  0.0 
    5 root       0 -20       0      0      0 S  0.0  0.0 
    7 root      rt   0       0      0      0 S  0.0  0.0 
    8 root      20   0       0      0      0 S  0.0  0.0 
    9 root      20   0       0      0      0 S  0.0  0.0 
   10 root      rt   0       0      0      0 S  0.0  0.0 
   12 root      20   0       0      0      0 S  0.0  0.0 
   13 root       0 -20       0      0      0 S  0.0  0.0 
   14 root      20   0       0      0      0 S  0.0  0.0 
   
   
[root@localhost 2020-3-13]# pstree
systemd─┬─AliYunDun───23*[{AliYunDun}]
        ├─AliYunDunUpdate───3*[{AliYunDunUpdate}]
        ├─2*[agetty]
        ├─aliyun-service───2*[{aliyun-service}]
        ├─atd
        ├─auditd───{auditd}
        ├─crond
        ├─dbus-daemon
        ├─dhclient
        ├─ntpd
        ├─polkitd───5*[{polkitd}]
        ├─rsyslogd───2*[{rsyslogd}]
        ├─sshd───sshd───bash───pstree
        ├─systemd-journal
        ├─systemd-logind
        ├─systemd-udevd
        └─tuned───4*[{tuned}]

杀死进程

图片.png

kill举例

Terminated :结束,终点

[root@localhost 2020-3-13]# sleep 1000 &
[1] 18529
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18529 pts/0    00:00:00 sleep
18530 pts/0    00:00:00 ps
[root@localhost 2020-3-13]# kill 18529
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18531 pts/0    00:00:00 ps
[1]+  Terminated              sleep 1000

pkill举例

[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18537 pts/0    00:00:00 ps
[root@localhost 2020-3-13]# sleep 1000 &
[1] 18538
[root@localhost 2020-3-13]# sleep 1000 &
[2] 18539
[root@localhost 2020-3-13]# sleep 1000 &
[3] 18540
[root@localhost 2020-3-13]# sleep 1000 &
[4] 18541
[root@localhost 2020-3-13]# sleep 1000 &
[5] 18542
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18538 pts/0    00:00:00 sleep
18539 pts/0    00:00:00 sleep
18540 pts/0    00:00:00 sleep
18541 pts/0    00:00:00 sleep
18542 pts/0    00:00:00 sleep
18543 pts/0    00:00:00 ps
[root@localhost 2020-3-13]# pkill sleep
[1]   Terminated              sleep 1000
[2]   Terminated              sleep 1000
[3]   Terminated              sleep 1000
[4]-  Terminated              sleep 1000
[5]+  Terminated              sleep 1000
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18547 pts/0    00:00:00 ps

更改进程(前台执行/后台执行)

末尾加上& ,表示挂在后台执行
jobs显示后台任务
图片.png

[root@localhost 2020-3-13]# sleep 100
^C
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18507 pts/0    00:00:00 ps
[root@localhost 2020-3-13]# sleep 100 &
[1] 18513
[root@localhost 2020-3-13]# ps
  PID TTY          TIME CMD
18481 pts/0    00:00:00 bash
18513 pts/0    00:00:00 sleep
18514 pts/0    00:00:00 ps

转到前台举例

[root@localhost 2020-3-13]# jobs
[root@localhost 2020-3-13]# sleep 1000 &
[1] 18549
[root@localhost 2020-3-13]# jobs
[1]+  Running                 sleep 1000 &
[root@localhost 2020-3-13]# sleep 1000 &
[2] 18550
[root@localhost 2020-3-13]# jobs
[1]-  Running                 sleep 1000 &
[2]+  Running                 sleep 1000 &
[root@localhost 2020-3-13]# fg 1
sleep 1000
^C
[root@localhost 2020-3-13]# jobs
[2]+  Running                 sleep 1000 &

用户管理

图片.png
图片.png

添加/删除用户

主组:默认下,每个用户默认创建的基本组
附加组:除了基本组外,用户可以属于的其他组
一个用户可以有很多组,但是主组只有一个.其余都是附加组

图片.png

/etc/passwd 文件

-g 指定用户的主组

stu 用户id:1001,组id:1001
stu3:用户id:1003,组id:1001
stu和stu3的主组是同一组 stu

[root@localhost home]# useradd -g stu stu3
[root@localhost home]# cat /etc/passwd | grep stu
stu:x:1001:1001::/home/stu:/bin/bash
stu2:x:1002:1002::/home/stu2:/bin/bash
stu3:x:1003:1001::/home/stu3:/bin/bash

/etc/group 文件

-G 指定用户所属附加组

stu除了主组外,TA的附加组 是stu2

[root@localhost home]# useradd -G stu stu2
[root@localhost home]# cat /etc/group | grep stu
Akuaner:x:1000:stu
stu:x:1001:stu2
stu2:x:1002:

/etc/shadow 文件

passwd 设置密码

新建用户无密码

[root@localh home]# cat /etc/shadow | grep stu3
stu3:!!:18336:0:99999:7:::
[root@localh home]# passwd stu3
Changing password for user stu3.
New password: 
Retype new password: 
passwd: all authentication tokens updated successfully.
[root@localh home]# cat /etc/shadow | grep stu3
stu3:$6$shDnKXpO$x.pN6HZDwGp0MmKXEMbYPpdkGkb/lAITw.fnzxNmVb0ZoSifWFnKS.PQP1KW5lE9b8eFhrWyQGzHk0nySlAN2/:18336:0:99999:7:::
查看原文

赞 0 收藏 0 评论 0

Akuaner 发布了文章 · 3月10日

Linux - Makefile & 库文件

前言

Linux ->工程管理(目录结构)

Object(目录):
 DataBase(目录):数据库操作
 Core(目录):项目核心代码
 DateData(目录):基础的业务逻辑
 Inter(目录):网络部分的代码
  .....
假设每个目录里有100个.c文件

gcc -o main 所有.c文件
此时若要编译,使用gcc就十分不方便了
而且,编译了一大坨以后,如果要修改其中一个文件,得把这一坨拉回来重新编译
引入了Makefile

Makefile文件

《跟我一起写Makefile》
makefile最直观的好处:只需要一个make命令,完全自动编译

新建makefile文件并使用

相当于gcc的集合体,把gcc的操作写在了makefile文件里,更具有条理性

[root@localhost 2020-03-09]# vim makefile
[root@localhost 2020-03-09]# ls
add.c  div.c  main.c  makefile  mux.c  my_math.h  sub.c
[root@localhost 2020-03-09]# make
[root@localhost 2020-03-09]# ls
add.c  div.c  main    main.o    mux.c  my_math.h  sub.o
add.o  div.o  main.c  makefile  mux.o  sub.c
[root@localhost 2020-03-09]# ./main 
a+b=32
a-b=8
a*b=240
a/b=1.666667
[root@localhost 2020-03-09]# make clean
rm *.o  main
[root@localhost 2020-03-09]# ls
add.c  div.c  main.c  makefile  mux.c  my_math.h  sub.c
/*makefile内部*/
main:main.o add.o div.o sub.o mux.o
    gcc -o main main.o add.o div.o sub.o mux.o
main.o:main.c
    gcc -c main.c
add.o:add.c
    gcc -c add.c
mux.o:mux.c
    gcc -c mux.c
sub.o:sub.c
    gcc -c sub.c
div.o:div.c
    gcc -c div.c

clean:
    rm *.o  main

其余部分代码

/*add.c*/
#include "./my_math.h"

int my_add(int a,int b)
{
    return a+b;
}
/*div.c*/
#include "./my_math.h"
#include <stdio.h> //printf
#include <stdlib.h> //存在结束exit(0)

double my_div(int a,int b)
{
    if(b==0)
    {
        printf("error");
        exit(0);
    }
    return (a*1.0)/b;
}    
/*my_math.h*/
#ifndef _MY_MATH_H
#define _MY_MATH_H

int my_add(int,int);

int my_sub(int,int);

int my_mux(int,int);

double my_div(int,int);

#endif

假设两个main函数共用部分文件

新建一个.c文件 run.c

/*run.c*/
#include "./my_math.h"
#include <stdio.h>
#include <stdlib.h>

int main(){
    printf("helloL%d",my_div(100,34)-my_add(1,20));
}
/*makefile文件*/
all:main run

run:run.o add.o div.o
    gcc -o run run.o add.o div.o
main:main.o add.o div.o sub.o mux.o
    gcc -o main main.o add.o div.o sub.o mux.o

add.o:add.c
    gcc -c add.c
mux.o:mux.c
    gcc -c mux.c
sub.o:sub.c
    gcc -c sub.c
div.o:div.c
    gcc -c div.c
main.o:main.c
    gcc -c main.c
run.o:run.c
    gcc -c run.c

clean:
    rm *.o  main

makefile简化写法

编译语句,编译器会自动推导

/*makefile*/
main:main.o add.o div.o sub.o mux.o

add.o:add.c
mux.o:mux.c
sub.o:sub.c
div.o:div.c
main.o:main.c

clean:
    rm *.o  main

默认cc编译器

[root@localhost 2020-03-09]# make
cc    -c -o main.o main.c
cc    -c -o add.o add.c
cc    -c -o div.o div.c
cc    -c -o sub.o sub.c
cc    -c -o mux.o mux.c
cc   main.o add.o div.o sub.o mux.o   -o main

强制使用gcc/g++编译器

首部加上CC=gcc

/*makefile*/
CC=g++
main:main.o add.o div.o sub.o mux.o

add.o:add.c
mux.o:mux.c
sub.o:sub.c
div.o:div.c
main.o:main.c

clean:
    rm *.o  main

进一步简化makefile

CC=g++
main:main.o add.o div.o sub.o mux.o
main.o add.o mux.o div.o sub.o:

clean:
    rm *.o  main

极简makefile写法⭐

CC=g++
file=main.o add.o mux.o div.o sub.o
main:$(file)
$(file):
clean:
    rm *.o  main

在不同目录下

[root@localhost 2020-03-09]# tree
.
├── main.c
├── makefile
├── Math
│   ├── add.c
│   ├── div.c
│   ├── mux.c
│   └── sub.c
└── my_math.h

VPATH:./Math
先在当前目录下搜索,再去Math目录下搜索
此时的main.c 的头文件"./Math my_math.h"

CC=g++
file=main.o add.o mux.o div.o sub.o
VPATH=.:./Math 
main:$(file)
$(file):
clean:
    rm *.o  main

为了防止生成过多的中间文件

执行完main以后执行cleanobj

CC=g++
file=main.o add.o mux.o div.o sub.o
VPATH=.:./Math

all:main cleanobj

main:$(file)
$(file):

clean:
    rm *.o  main
cleanobj:
    rm *.o

图片.png

库文件

库文件:将用户写好的程序打包成一个整体,当其他模块或用户使用时,只需要有这个库文件就OK

libc.so -->stdio.h string.h math.h rand.h time.h
libstdc++.so -->STL

静态库

windows : .lib
Linux : .a

生成-使用步骤

生成:

 1.将所有源代码(不含有main)文件编译成中间文件(.o)
 2.使用命令 ar crv libxxx.a *.o

gcc -c *.c
ar crv libxxxxx.a *.o
//注意 *.o 会把所有的.o文件打包到库里
//请确保当前文件夹.o文件都是你需要的

使用:

gcc -o main main.c -L库的路径 -l库的名称
//如果没有给出库的路径,则会去默认路径下查找 /lib 或 /usr/lib

gcc -o main main.c -L./Math -lMyMathName

参考代码

[root@izm5eb8f6yfdzvy9a9acbfz 2020-03-09]# ls
main  main.c  makefile  Math
[root@izm5eb8f6yfdzvy9a9acbfz 2020-03-09]# cd Math
[root@izm5eb8f6yfdzvy9a9acbfz Math]# ls
add.c  div.c  mux.c  my_math.h  sub.c
[root@izm5eb8f6yfdzvy9a9acbfz Math]# gcc -c *.c
[root@izm5eb8f6yfdzvy9a9acbfz Math]# ls
add.c  div.c  mux.c  my_math.h  sub.o
add.o  div.o  mux.o  sub.c
[root@izm5eb8f6yfdzvy9a9acbfz Math]# ar crv libMyMathName.a *.o
a - add.o
a - div.o
a - mux.o
a - sub.o
[root@localhost Math]# ls
add.c  div.c  libMyMathName.a  mux.o      sub.c
add.o  div.o  mux.c            my_math.h  sub.o
[root@localhost Math]# cd ..
[root@localhost 2020-03-09]# ls
main.c  makefile  Math
[root@localhost 2020-03-09]# gcc -o main main.c
/tmp/ccmTewMT.o: In function `main':
main.c:(.text+0x21): undefined reference to `my_add'
main.c:(.text+0x41): undefined reference to `my_sub'
main.c:(.text+0x61): undefined reference to `my_mux'
main.c:(.text+0x81): undefined reference to `my_div'
collect2: error: ld returned 1 exit status
[root@localhost 2020-03-09]# gcc -o main main.c -L./Math -lMyMathName
[root@localhost 2020-03-09]# ls
main  main.c  makefile  Math
[root@localhost 2020-03-09]# ./main
a+b=32
a-b=8
a*b=240
a/b=1.666667

图片.png

共享库(动态库)

windows: .dll
Linux : .so

生成-使用-执行步骤

生成

gcc -shared -fPIC -o libxxxxxx.so 所有功能代码的源代码

[root@localhost Math]# ls
add.c  div.c  libMyMathName.a  mux.c  my_math.h  sub.c
[root@localhost Math]# gcc -shared -fPIC -o libActiveMathName.so *.c
[root@localhost Math]# ls
add.c  libActiveMathName.so  mux.c      sub.c
div.c  libMyMathName.a       my_math.h

使用

gcc -o main main.c -L库的路径 -l库的名称

gcc -o main main.c -L./Math -lActiveMathName
[root@izm5eb8f6yfdzvy9a9acbf

执行

动态库在使用后,就已经在main里了,但是执行的时候,必须指明库所在路径
默认路径: /lib /usr/lib
通过环境变量来设置系统加载动态库的搜索路径:LD_LIBRARY_PATH
export LD_LIBRARY_PATH=.os所在路径

[root@locaohost 2020-03-09]# ./main
./main: error while loading shared libraries: libActiveMathName.so: cannot open shared object file: No such file or directory
[root@locaohost 2020-03-09]# ls
main  main.c  makefile  Math
[root@locaohost 2020-03-09]# cd Math
[root@locaohost Math]# pwd
/home/Akuaner/2020-03-09/Math
[root@locaohost Math]# export LD_LIBRARY_PATH=/home/Akuaner/2020-03-09/Math
[root@locaohost Math]# echo $LD_LIBRARY_PATH 
/home/Akuaner/2020-03-09/Math
[root@locaohost Math]# cd ..
[root@locaohost 2020-03-09]# ./main
a+b=32
a-b=8
a*b=240
a/b=1.666667

export LD_LIBRARY_PATH=
这个指令是临时性的,要想永久的修改该路径,可以添加到家目录(~)下的.bashrc文件中

查看原文

赞 0 收藏 0 评论 0

Akuaner 发布了文章 · 3月9日

Linux - gdb调试

调试

调试工具:gdb的使用

编译后版本

编译后的成果分为两个版本:

debug版本:调试版本 -->程序员使用
release版本:最终发行版本 -->最终用户使用

gcc默认生成的是release版本的可执行文件.out

如果一步编译时要生成debug版本,需要加上-g
如果是分步生成可执行文件,则需要在编译阶段加入-g,生成debug版本的中间文件
gcc -c main.c -g //分步
gcc -o main main.c -g

gdc调试,必须是debug版本的可执行文件,才能调试

gdb调试铺垫

vim 写多个代码

多个.c文件,一个写函数,一个写main函数,那么此刻会再创建一个.c文件,用于写声明和多余头文件

#ifndef _My_Math_H
#define _My_Math_H
#endif
//#ifndef 和#endif 是防止头文件重名

gcc -g编译成debug版本.out

显示代码

gdb filename 打开filename

l 显示main函数所在的文件代码
list filename:line 显示filename文件line行开始的代码
显示symbols /home/....
(gdb) l    //输入l,查看main函数
(gdb) list file2.c:1  //查看file2文件,从第1行开始

断点管理⭐

断点管理:

b 行号 给指定的行添加一个断点
b 函数名 给指定的函数的有效第一行添加一个断点
info b 显示所有断点的信息
disable 断点号 使得某断点无效
enable 断点号 使某断点有效
d 断点号 删除断点
增加断点
(gdb) b 5 //默认加到最近显示的文件中
(gdb) b main //给main函数加断点
查看断点
(gdb)info b
管理断点
(gdb)disable 1 //使得1号断点无效 keep y -> keey n
(gdb)enable 1 //使得1号断点有效
删除断点
(gdb)d 2 //删除2号断点

调试过程(单步执行)

调试选择

r 开始执行,执行到运行过程中第一个断点处停止
n 单步执行 next 目的:查看变量的值
s 逐语句执行(进入到即将被执行的函数中去)
finish 跳出函数
c 继续执行,直到下一个断点
q 退出调试

查看变量的值

单步显示
常见变量
p valname 查看变量的值
p &valname 现实变量的地址
p 表达式 显示表达式结果
p 函数(实参) 现实函数执行结果
ptype valname 查看变量/函数类型
数组和指针
p *ptr 显示数组首元素 (ptr体制存储的值)
p *ptr@len 显示数组所有元素的值
p arr 打印数组所有元素的值
p ptr 查看变量ptr的值 (数组的首地址)
int arr[10]={12,34,45};
int *ptr = arr;
结构体变量
struct Node
{
  int data;
  struct Node *next;
}
p head 显示head里所有的data和next
p head.data
p head.next
struct Node head
p p->data;
p p->next;
struct Node *p=&head;
自动显示(操作类似断点)
display 以上参数 自动显示(类似于监视器)
info display 显示display信息
undisplay + 编号(display的) 删除指定的自动显示
(gdb)r
(gdb)n
(gdb)p a //查看a变量的值
(gdb)p &a //查看a的地址
(gdb)n
(gdb)p b
(gdb)p &b
(gdb)p a+b
(gdb)p my_sub(a,b);

显示函数调用栈

有些函数是共用的,通过bt来判断是那个途径调用的

bt 显示函数调用栈 显示函数调用的经过
图片.png
查看原文

赞 0 收藏 0 评论 0

Akuaner 发布了文章 · 3月7日

Linux - gcc 和g++

检查和安装

查看是否有安装

which gcc
which g++
which gdb

查看版本号

gcc -version

安装

从网上下载一个包
wget -O /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo
在包中选择要下载的东西

yum install gcc
yum install g++
yum install gdb

gcc的介绍

本质:
linux是把.c文件 转化为.out可执行文件 ->ELF格式
window下,是把.c文件转化为.exe可执行文件
图片.png

gcc:四个过程

图片.png
编译阶段:

预编译: gcc -E file.c -o file.i
 .c文件 转化为 .i文件
编译: gcc -S file.i
生成一个 .s文件 ,变成汇编程序
汇编:  gcc -c main.s
生成一个.o文件,可重定位的二进制文件

连接阶段:

连接: gcc -o newname oldname.o
生成了一个可执行文件newname
   gcc file.o
  默认生成了可执行文件a.out

因为下面的操作覆盖上面的操作,

gcc -E name.c  //得到.i文件
gcc -S name.c  //得到.s文件
gcc -c name.c  //得到.o文件
gcc -o name.c  //得到.out文件

常用用法:

单文件

gcc -o filename oldname.c
//此时filename是.out执行文件,而不是.c
执行文件: 编译完了之后运行该程序即可

[root@localhost 2020-3-7]# vim hello.c
[root@localhost 2020-3-7]# gcc -o newname hello.c[root@localhost 2020-3-7]# ls
hello.c  newname
[root@localhost 2020-3-7]# ./newname
hello
[root@localhost 2020-3-7]# 
多个文件编译连接成一个.out

gcc -o projectname main.c file.c file2.c
//注意事项:一个工程中只能有一个main函数

不同语言在四个过程下的不同

c语言与C++编译的不同:

C语言在函数前只需要加下划线即可/C++还需要看他的参数顺序,参数个数,参数类型等,所以才有了函数的重载的概念

java与c类语言在汇编的不同

java在汇编过程中,存在一个虚拟机的概念 .class需要gbm去读取执行,优点是可以跨平台,本质是在不同平台上提供了不同的解释器
C++就不需要,可以直接把汇编指令翻译成二进制,缺点就是不能跨平台,优势是速度快
《程序员的自我修养》

.o文件 (ELF格式)

图片.png

o文件的组成

readelf -h main.o  //查看头部的信息
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
....
  Size of this header:    64 (bytes)
....
objdump -h main.o //查看文件的段分布
main.o:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
  0 .text         0000000d  0000000000000000  0000000000000000  00000040  2**0
                  CONTENTS, ALLOC, LOAD, READONLY, CODE
  1 .data         00000014  0000000000000000  0000000000000000  00000050  2**2
                  CONTENTS, ALLOC, LOAD, DATA
  2 .bss          0000000c  0000000000000000  0000000000000000  00000064  2**2
                  ALLOC
  3 .comment      0000002e  0000000000000000  0000000000000000  00000064  2**0
                  CONTENTS, READONLY
  4 .note.GNU-stack 00000000  0000000000000000  0000000000000000  00000092  2**0
                  CONTENTS, READONLY
  5 .eh_frame     00000038  0000000000000000  0000000000000000  00000098  2**3
                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, DATA
.bss是.data的一部分
.text 存放指令
.data 存放数据

把重定位二进制文件.o进行连接

图片.png

在汇编后,会生成多个可重定位的二进制文件
多个.c/.cpp文件,都是独立编译的,在连接过程中在组装到一起
在其中一个.o文件中可能需要其他.o文件的方法
这个时候就需要重定位,把调用点的标识,改成需要调用的地址
让该方法最终在其他文件中可以被使用

什么属于数据?

数据:全局变量和静态变量,且初始化不为零
函数内部的非static变量,是指令
图片.png

gcc和g++的区别

gcc 默认连接 C库,把.cpp和.c分开编译
g++ 默认连接C++,都当做.cpp来编译
他们俩是相通的

//如果非要用gcc编译.cpp文件,命令把C++库加上就行
gcc main.cpp -o main -lstdc++

g++和gcc指令一致,文章中g++替换gcc即可

常见错误

错误-未定义符号:gcc编译链接时,少了某些文件
linux下定义(实现) :必须包含.c文件,所以纯.h文件是会报错的

查看原文

赞 1 收藏 1 评论 0

Akuaner 发布了文章 · 3月7日

Linux - 管道+过滤

过滤查看

过滤命令

过滤命令:grep 包含内容(过滤条件)
grep过滤经常结合管道使用,比如过滤查看

管道命令

格式: 命令1|命令2
将前一个命令的输出,作为后一个命令的输入
ls | grep 内容
cat filename | grep 内容

[root@locahost 2020-3-6]# ls
a.cpp  b.cpp  c.cpp  chong.c  newtar.tgz  rechong.c
[root@locahost 2020-3-6]# ls | grep .c
a.cpp
b.cpp
c.cpp
chong.c
rechong.c
[root@locahost 2020-3-6]# ls
a.cpp  b.cpp  c.cpp  chong.c  newtar.tgz  rechong.c
[root@locahost 2020-3-6]# ls -l | grep n
-rw-r--r-- 1 root root  10 Mar  7 12:20 chong.c
-rw-r--r-- 1 root root 458 Mar  7 14:53 newtar.tgz
-rw-r--r-- 1 root root   0 Mar  7 12:21 rechong.c
查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 4 次点赞
  • 获得 2 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 2 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2月14日
个人主页被 148 人浏览