本文为Linux系统编程自学整理,方便个人随时查看,主要参考黑马程序员[Linux系统编程]
本部分为一些Linux基础知识
Linux系统文件类型
Linux系统文件类型: 7/8 种
文件类型 | 表示方法 |
普通文件 | - |
目录文件 | d |
字符设备文件 | c |
块设备文件 | b |
软连接 | l |
管道文件 | p |
套接字 | s |
未知文件 |
文件权限
![](https://img-blog.csdnimg.cn/img_convert/d23d499d77e10a68aae21fb3ee8eb762.jpeg)
上面图片中是目录项详细信息(ls -l)
从左到右依次为:
文件权限 硬链接计数 所有者 所属组 大小 时间 文件名/文件夹名
权限具体展开:
-rw-rw-r--
1234567890
从左到右:1代表文件类型,234代表所有者读写执行权限,567代表同组用户读写执行权限,890代表其他人读写执行权限
创建修改用户和用户组
whoami 查看当前用户
sudo adduser newusername 添加新用户
chown username filename 修改文件所有者
su username 切换当前用户为username
chomd 修改权限操作
文字设定法
chmod [who] [+|-|=] [mode] filename
who可以是下述字母中的任一个或者它们的组合
u 表示”用户(user)”,即文件或目录的所有者
g 表示”同组(group)用户”,即与文件所有者有相同组ID的所有用户
o 表示”其他(others)用户”
a 表示”所有(all)用户”,它是系统默认值
操作符号可以是:
+ 添加某个权限
- 取消某个权限
= 赋予给定权限并取消其他所有权限(如果有的话)
如下所示,给file2文件添加执行权限
![](https://img-blog.csdnimg.cn/img_convert/609b0b57c583b28b3b575195c24de3fd.png)
数字设定法
chmod 操作码 文件名
对于file2的权限
-rw-rw-r--
421421421
权限都为二进制编号
对此文件设置为如下权限,操作码就是764
所有者 rwx 7
所有者所在组 rw 6
其他用户 r 4
![](https://img-blog.csdnimg.cn/img_convert/7c723798a8e09281b8b6342d7145ad93.png)
Linux系统目录
目录 | 存放的东西 |
bin | 存放二进制可执行文件 |
boot | 存放开机启动程序 |
dev | 存放设备文件: 字符设备、块设备 |
home | 存放普通用户 |
etc | 用户信息和系统配置文件 passwd、group |
lib | 库文件:libc.so.6 |
root | 家目录 |
usr | 用户资源管理目录 |
其他
ps aux | grep 条件 结果至少有一个,就是当前查询进程
![](https://img-blog.csdnimg.cn/img_convert/b0c6a079601c7f0746ec1a232c7fbef6.png)
kill 杀死进程
ifconfig 查看网卡信息
man 系统参考手册
man n name 在系统手册第n章查看name
vim基本操作
vim有三种模式:命令模式、文本模式、末行模式
![](https://img-blog.csdnimg.cn/img_convert/b50ff6247c17e1429de9aaf2b012bdbc.png)
以下均为命令模式下操作:
命令 | 含义 |
x | 删除光标所在字符,工作模式不变 |
D | 删除光标所在位置到行末,工作模式不变 |
0(数字) | 光标移到行首,工作模式不变 |
$ | 光标移到行尾,工作模式不变 |
d0 | 删除光标所在位置到行首,工作模式不变 |
d$ | 删除光标所在位置到行末,工作模式不变 |
line-G | 行跳转 |
gg | 跳转首行 |
G | 跳转末行 |
% | 光标处于左大括号时,使用%跳转到对应右大括号,再按%跳回去。 其他括号也可以这样 |
自动缩进
cd /etc/vim
sudo vi vimrc
在 vimrc 配置文件的底部追加以下命令:
syntax on //设置语法高亮,一般默认有,可不用添加此句
set tabstop=4 //设置制表符宽度为 4
set softtabstop=4 //设置软制表符宽度为 4
set shiftwidth=4 //设置缩进的空格数为 4
set autoindent //设置自动缩进
set cindent //设置使用 c/c++ 语言的自动缩进方式
set nu //设置在左侧显示行号
删除
命令模式下:
r 替换光标选中字符
v 进入可视模式,选择一片区域按d剪切
dd 剪切光标所在行
n+dd 剪切从光标开始的n行
复制粘贴
yy 复制光标所在行
p 向后粘贴剪切板内容
P 向前粘贴剪切板内容
n-yy 复制光标所在位置的n行,包括光标所在行
查找和替换
查找
/+findname 命令模式下查找
按回车键启动查找后,按n,会自动找下一个,N跳到上一个
查找光标所在单词
光标在目标单词上时,*或者#查找下一个,这里不要求光标必须在首字母上
替换:末行模式下进行
单行替换
光标置于待替换行, :s /待替换词/替换词
全文替换
:%s /待替换词/替换词 默认替换每行的首个,一行有多个目标词时,后面的不会变
:%s /待替换词/替换词/g 真正意义上的全局替换
区域替换
:24,35s/待替换词/替换词/g 替换24-35行之间的目标词
但是有个缺点是:不是替换单词,而是替换相应输入的字母(慎用)
其他
末行模式下
历史命令
Ctrl-p 上一条命令
Ctrl-n 下一条命令
分屏,末行模式下
:sp 水平分屏
:vsp 竖直分屏
分屏命令+filename,分屏并打开这个文件
分屏后屏幕切换,Ctrl-w-w
使用:q退出光标所在窗口
使用:qall退出所有窗口
命令模式下
u 撤销操作
Ctrl-r 反撤销
从vim中跳转manpage
将光标放在待查看单词上,按K,默认看第一卷
n+K,查看第n卷
查看宏定义
光标放在待查看词上,[+d即可查看
gcc编译
编译四步骤
gc编译可以执行程序 4步骤:预处理、编译、汇编、链接
![](https://img-blog.csdnimg.cn/img_convert/c211a4d521df014b82685e27f7c0dab4.png)
![](https://img-blog.csdnimg.cn/img_convert/24ca87da61a8be34efa38c608450fa17.png)
地址回填和数据段合并(链接阶段)
链接阶段会做地址回填:将链接后的main的地址填入
地址回填:写在源代码里的函数,相对main函数偏移是一定的,链接时,回填main函数地址之后,其他源代码里的函数也就得到了地址。
Fun1()和fun2()都是自己写的函数
数据段合并:节省空间
32位操作系统
0-4G
![](https://img-blog.csdnimg.cn/img_convert/745ca1c838472fb1431a09cc9d135757.png)
32位操作系统一个a.out文件会有0-4g的地址空间
.text是代码段(只读);.rodata:只读数据段;.data:数据段;
.data和.bss的区别是一个是未初始化的,一个是初始化为非零
Heap:堆;stack:栈
堆是从低地址到高地址;栈是从高地址到低地址。两者中间的位置越来越小。
动态库内存加载位置就是在堆和栈之间
环境变量和main函数的参数在栈的上方--导致动态库环境变量失效原因
系统调用可以完成从用户区到内核区的切换
数据段合并(节省空间)
不进行合并的话,若.rodata使用4b,.text使用1kb,但使用内存一次最少用4kb(使用磁盘存储使用512)
text和rodata都为可读,合并为一个
.data和.bss都为可读可写,合并为一个,
内存中其实有很多个段,数据段合并不止是这几个段进行合并
编译常用参数
-I 指定头文件所在目录位置
gcc -I ./hellodir hello.c -o hello(其中头文件hello.h在文件夹hellodir中)
-c 只做预处理,编译,汇编。得到二进制文件
-g 编译时添加调试文件,用于gdb调试
-Wall 显示所有警告信息
-D 向程序中“动态”注册宏定义
-l 指定动态库库名
-L 指定动态库路径
动态库和静态库
静态库在文件中静态展开,所以有多少文件就展开多少次,非常吃内存,100M展开100次,就是1G,但是这样的好处就是静态加载的速度快
使用动态库会将动态库加载到内存,10个文件也只需要加载一次,然后这些文件用到库的时候临时去加载,速度慢一些,但是很省内存
动态库和静态库各有优劣,根据实际情况合理选用即可。但由于计算机的发展,速度可忽略了,使用动态库更多
静态库
静态库名字以lib开头,以.a结尾
例如:libmylib.a
静态库生成指令
ar rcs libmylib.a file1.o
制作和使用
隐式声明: 万恶之源:C语言中的隐式函数声明_smstong的博客-CSDN博客_c语言函数隐式声明
制作一个包含加法、除法、减法的动态库;指定头文件位置;使用头文件守卫
源代码
test.c为主函数;add.c、sub.c、div.c为调用函数
1 # include<stdio.h>
2 # include<stdlib.h>
3 # include<string.h>
4 # include<unistd.h>
5 # include<pthread.h>
6
7 int add(int, int);
8 int sub(int, int); //可做成头文件,后面有介绍
9 int div1(int, int);
10
11 int main() {
12 int a = 15;
13 int b = 5;
14 printf("%d - %d = %d\n",a,b,sub(a,b));
15 printf("%d / %d = %d\n",a,b,div1(a,b));
16 printf("%d + %d = %d\n",a,b,add(a,b));
17 return 0;
18 }
1 int div1(int a, int b){
2 return a / b;
3 }
1 int sub(int a,int b){
2 return a-b;
3 }
1 int add(int a,int b){
2 return a+b;
3 }
编译生成.o文件
gcc -c add.c -o add.o
gcc -c sub.c -o sub.o
gcc -c div.c -o div1.o
制作静态库(其中test.c在当前cppcode目录,.o文件在staticlib目录)
ar rcs libmymath.a add.o sub.o div1.o
1 # include<stdio.h>
2 # include<stdlib.h>
3 # include<string.h>
4 # include<unistd.h>
5 # include<pthread.h>
6 # include"mymath.h"
7
8 int main() {
9 int a = 15;
10 int b = 5;
11 printf("%d - %d = %d\n",a,b,sub(a,b));
12 printf("%d / %d = %d\n",a,b,div1(a,b));
13 printf("%d + %d = %d\n",a,b,add(a,b));
14 return 0;
15 }
在INC目录下创建mymath.h
1 #ifndef _MYMATH_H_
2 #define _MYMATH_H_
3
4 int add(int,int);
5 int sub(int,int);
6 int div1(int,int);
7
8 #endif
gcc test.c ./staticlib/libmymath.a -o a.out -I ./INC
./a.out
15 - 5 = 10
15 / 5 = 3
15 + 5 = 20
动态库
没有调用到动态库内部的函数的时候,动态库不会加载使用;只有调用到动态库的内部的函数的时候,动态库才会被加载到内存,同时绑定地址;
动态库要求生成与位置无关的代码(函数调用之前需要将其地址固定)
动态库里的函数在地址回填时与自己制作的函数不同,会用一个@plt来标识,当动态库加载到内存时,再用加载进去的地址将@plt替换掉。
制作
生成位置无关的.o文件
gcc -c add.c -o add.o -fPIC
使用这个参数过后,生成的函数就和位置无关,挂上@plt标识,等待动态绑定
使用gcc -shared制作动态库
gcc -shared -o lib库名.so add.o sub.o div.o
编译可执行程序时指定所使用的动态库。-l:指定库名 -L:指定库路径
gcc test.c -o a.out -l mymath -L ./lib -I ./INC
运行可执行程序./a.out
此时直接执行4会出错,因为要提供动态库所在目录位置
解决方式:
【1】 通过环境变量: export LD_LIBRARY_PATH=动态库路径
./a.out 成功!!! (临时生效, 终端重启环境变量失效)
失效的原因是 一个程序会生成一个地址空间,环境变量也在这个空间中,一旦终端关闭,程序失效,地址空间也没了
【2】 永久生效: 写入 终端配置文件。 .bashrc 建议使用绝对路径。
1) vi ~/.bashrc
2) 写入 export LD_LIBRARY_PATH=动态库路径 保存
3). .bashrc/ source .bashrc / 重启终端 ---> 让修改后的.bashrc生效
4)./a.out 成功!!!
【3】 拷贝自定义动态库 到 /lib(标准C库所在目录位置)
【4】 配置文件法
sudo vi /etc/ld.so.conf
2) 写入 动态库绝对路径 保存
sudo ldconfig -v 使配置文件生效。
4)./a.out 成功!!!--- 使用ldd a.out 查看