Linux编程基础

一、Linux目录结构

/bin:二进制文件,可执行程序,shell命令
/dev:在linux下一切皆文件
/lib:linux运行的时候需要加载的一些动态连接库
/mnt:手动的挂载目录
/media:外设的自动挂载目录
/root:linux的超级用户的家目录
/usr:unix system resource
头文件:stdio.h stdlib.h
/usr/local:用户自己安装的用户程序
/etc:存放配置文件
/etc/passwd:当前系统下的用户信息
/etc/group:当前系统下的用户组
/opt:安装第三方应用程序
/home:linux操作系统所有用户的家目录
用户家目录:/home/xsw
/tmp:存放临时文件(重启系统会清空)

相对路径和绝对路径

.和…:
.代表当前目录:./
…代表当前目录的上一级目录

二、GCC

GCC工作流程

预处理:--E
	宏替换
	头文件展开
	注释去掉
编译:--S
汇编:-C
链接

在这里插入图片描述

GCC常用参数

-v/-version:查看版本
**-I:编译的时候指定头文件路径(当前工程文件夹下没有指定的头文件)
	gcc helloworld.c -I /.../... -o helloworld
-c:生成二进制文件 helloworld.o
	gcc helloworld.c -c
-o:指定生成的文件的名称
	gcc helloworld.c -o helloworld.i**
-g:gdb调试的时候需要
	gcc helloworld.c -o helloworld -g
-D:在编译的时候指定一个宏(测试的时候用到)
	gcc helloworld.c -o helloworld -D DEBUG
-Wall:添加警告信息、
-On:优化代码,n是优化级别:1,2,3

三、静态库和动态库的制作和使用

工程管理文件目录:
include lib main.c src
include放置头文件.h
lib放置库.a .so
main.c放置主函数文件,用于调用库(包含库函数的头文件即可)
src放置源码

静态库的制作和使用

1、命名规则:libtest.a
lib
xxx - 库的名字
.a
2、制作步骤:
	制作原材料:源代码c文件,cpp文件
	将.c文件生成.o文件:gcc a.c b.c -c
	将.o文件打包:ar rcs 静态库的名字 原材料
		ar rcs libtest.a a.o b.o
	查看库里面文件:nm libtest.a
3、库的使用
	编译主函数文件:
	gcc main.c -I ./include/ -L ./lib/ -l test. -o app
	注意:-l后面的参数为:去掉静态库文件名的lib和.a后缀即可

src文件夹下add.c文件

#include "head.h"
int add(int a , int b)
{
        int result;
        result = a+b;
        return result;
}

main.c文件

#include <stdio.h>
#include "head.h"
void main()
{
        int a=2,b=3,sum;
        sum = add(a,b);
        printf("sum= %d\n",sum);
}

include文件夹下head.h文件

#ifndef __HEAD_H
#define __HEAD_H
int add(int a,int b);
int sub(int a ,int b);
int mul(int a,int b);
int div(int a,int b);
#endif

动态库的制作和使用

1、命名规则:libxxx.so
2、制作步骤:
	将源文件生成.o文件:gcc a.c b.c -c fpic
	打包:gcc -shared -o libxxx.so a.o b.o
3、库的使用
	gcc main.c -I ./include -L ./lib -l test -o app
	编译完成以后并不能运行可执行程序
	加载动态链接库:(两种方法)
	第一种方法:设置环境变量:
		(1)、临时设置:在终端 :export LD_LIBRARY_PATH=动态链接库路径(关掉终端以后还是无法加			载,链接不到动态库)
		export LD_LIBRARY_PATH=新加入动态链接库:$LD_LIBRARY_PATH(拼接已经存在的环境变量,放防止覆盖)
		(2)、永久设置:
		*用户级别:vim ~/.bashrc(只针对当前用户生效)
			添加:export LD_LIBRARY_PATH=/home/xsw/mytest/lib
			重启终端或者source ~/.bashrc重新加载环境变量
		*系统级别:vim /etc/profile(针对所有用户)
			添加:。。。
			重启终端或者source /etc/profile
	第二种方法:更新/etc/ld.so.cache文件列表
		(1)找到配置文件:
			/etc/ld.so.conf
			把动态库的绝对路径添加到文件中
			/home/xsw/mytest/lib
		(2)执行一个命令
			sudo ldconfig -v(-v输出信息)

四、makefile

makefile的编写

1、makefile中的规则
	gcc a.c b.c c.c -o app
	三部分:目标,依赖,命令
	目标:依赖
	(tab缩进)命令
	app:a.c b.c c.c
		gcc a.c b.c c.c -o app
	makefile中由一条或多条规则组成
2、makefile的编写
	其中main.c add.c sub.c head.h makefile 都存放在一个路径下面
	第一个版本:

在这里插入图片描述

	缺点:只更改一个c文件时,也会重新编译所有文件,makefile效率太低
	第二个版本

在这里插入图片描述

	优点:如果只改动add.c则再次编译只编译add.c,即只执行gcc add.c -c 和gcc main.o add.o sub.o -o app
	缺点:冗余
	工作原理:
		(1)检测依赖是否存在:向下搜索下边的规则,如果有规则是用来生成查找的依赖的,执行规则中的								命令
		(2)依赖存在,判断是否需要更新:原则上,目标的时间(文件最后更改时间)要大于依赖的时间;反之,则更新
	第三个版本(使用变量)
	(1)、自定义变量
		obj = a.o b.o c.o
		obj = 10
		变量的取值:aa = $(obj)
	(2)、makefile自带的变量:大写
		CPPFLAGS
		CC
	(3)、自动变量(三个)
		$@:规则中的目标
		$<:规则中的第一个依赖
		$^:规则中所有的依赖
		自动变量只能在规则的命令中使用

在这里插入图片描述

		模式匹配:
		%.o:%.c
		%用于自动替换,比如当执行完第一条规则需要main.o时,该命令被替换为:main.o:main.c
		缺点:可移植性性比较差
	第四个版本(使用函数) 
		*makefile中所有的函数都有返回值
		(1)、查找指定目录下指定类型的文件:wildcard
			src = $(wildcard ./*.c)
			注释:查找当前目录下的.c文件
		(2)、匹配替换:patsubst
			obj = $(patsubst %.c,%.o,$(src))
			注释:将.c文件替换为.o文件,其中.c文件从src中寻找

在这里插入图片描述

		缺点:不能清除项目
		第五个版本(清理项目)

在这里插入图片描述

			(1)、编写一个清理项目的规则:clean
				clean:
					rm *.o
				注释:该规则没有依赖
				如果需要执行该规则,则执行make clean
			(2)、声明伪目标:(如果在当前目录下创建文件clean,则make clean会报,clean是最新的,规则中的命令不工作)
				.PHONY:clean
			(3)、让make生成不是终极目标的目标:
				make 目标名
			(4)、-表示如果本条命令执行失败,跳过错误执行下一条命令;-f表示强制执行

五、gdb调试

1、gcc a.c b.c c.c -o app
gcc a.c b.c c.c -o app -g
-g:会保留函数名和变量名
2、启动gdb
gdb 可执行程序的名字
a. gdb app
b. 给程序传参:set args xxx xxx
在这里插入图片描述
3、查看代码 :
测试用例:
test4
list或者l(默认显示main函数里的代码)
show listsize(查看敲一次list显示源码的行数)
set listsize 10(设置敲一次list显示源码的行数)
list 函数名(显示函数的信息)
list 文件名:函数名
list 文件名:行号
4、断点操作 - break / b
设置断点:
break/b + 行号
break/b + 函数名
break/b + 文件名:行号
break/b + 文件名:函数名
查看断点:info/i b
删除断点:
delete/d num(断点编号)
删除多个:
d num1-num6
设置断点无效:dis 断点编号
断点生效:ena 断点编号
设置条件断点:break/b 行号 +条件(if i==10)
注:条件断点只能打在for循环内部,不能打在for起始。
5、调试相关命令:
让gdb跑起来:
start/s:运行一行停止,停在main()的下一行大括号处
run/r:停在第一个断点的位置
打印变量的值:print/p 变量名
打印变量的类型:ptype 变量名
向下单步调试:
next/n(遇到函数不会进入函数体)
step/s(遇到函数会进入函数体内部)
跳出函数体:finish
如果出不去,看一下函数体中的循环中是否有断点,如果有删掉,或者设置无效。
继续运行gdb,停在下一个断点的位置:continue/c
退出gdb:quit/q
变量的自动显示:
display 变量名
取消:undisplay 编号
i display
从循环体直接跳出:
until
循环体内部不能有断点
直接设置变量等于某一个值(多用于循环体内部):
set var 变量名 = value
set var i=5
查看STL的容器(如map、vector)中的数据:
首先下载一个GDB脚本.
启动GDB,执行source ~/stl-views.gdb(根据具体存放路径)
然后按照下列命令即可查看容器内容
命令列表

六、文件IO(系统函数)

预备知识:
文件描述符图示说明
1、open/close
(1)函数原型:
int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_t mode);
注:mode_t为八进制数
(2)参数:
a、flags
必选项O_RDONLY,O_WRONLY,O_RDWR
可选项:
创建文件:O_CREAT
创建文件时检测文件是否存在:O_EXCL
如果文件存在,返回-1
必须与O_CREAT一起使用
追加文件:O_APPEND(如果不用改函数直接写数据,指针指在文件开头,使用该函数,再写数据时,指针指在文件末尾,继续写数据,不会覆盖原数据)
文件截断:O_TRUNC(清空文件)
设置非阻塞:O_NONBLOCK
b、mode:当flags包含O_CREAT参数时,mode用于定义新创建的文件的权限
新创建的文件权限确定:mode & ~umask(可以设置:umask 0002)
c、返回值:文件描述符
(3)使用:int fd = open(…);
open实现
2、read
(1)函数原型:ssize_t read(int fd,void *buf,size_t count);
(2)参数:
fd:(文件描述符)open的返回值
buf:缓冲器,存储要读取的数据
count:缓冲区能够存放的最大字节数sizeof(buf)
size_t为一个无符号整型
(3)返回值:ssize_t为一个有符号整型
-1:失败
成功:
>0:读出的字节数
=0:文件读完了
3、write
(1)函数原型:ssize_t write(int fd,void *buf,size_t count);
(2)参数:
fd:open的返回值
buf:要写到文件的数据
count:strlen(buf),有效字节数,读取到\0的字符串长度
(3)返回值:
-1:失败
>0:写入到文件的字节数
练习:有一个很大的文件,open,数据读出来,read,读出的数据写到另一个文件中。
test6
4、lseek
(1)函数原型:off_t lseek(int fd,off_t offset,int whence);
(2)参数:
whence:
SEEK_SET:头部
SEEK_CUR:当前位置
SEEK_END:尾部
返回值:文件开头到当前文件指针处的字节数
(3)使用:
a、文件指针移动到头部:
lseek(fd,0,SEEK_SET);
b、获取文件指针当前位置:
int len = lseek(fd,0,SEEK_CUR);
c、获取文件长度
int len = lseek(fd,o,SEEK_END);
d、文件拓展
需求:文件原大小100B,拓展为1100B(拓展大小1000字节)
首先,设置偏移量:lseek(fd,1000,SEEK_END);
最后做一个写操作:write(fd,“a”,1);

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>
#include <fcntl.h>

int main(int argc,const char* argv[])
{
        int fd = open("english.txt",O_RDWR);
        if(fd == -1)
        {
                perror("open");
        }
        int len = lseek(fd,1000,SEEK_END);
        printf("len=%d\n",len);
        write(fd,"a",1);
        close(fd);
        return 0;
}

5、perror和errno
(1)函数原型:void perror(const char *s);
(2)参数:const char *s,为字符串
(3)注解:当调用了open、read或者write函数出错时,全局变量errno会被赋值,不同的值对应不同的错误信息,调用perror函数打印errno对应的错误信息,打印格式为:字符串s+ :+空格+错误信息
(4)例:

int fd = open("english",O_RDWR);
if(fd == -1)
{
        perror("open");
}

6、阻塞和非阻塞
(1)阻塞和非阻塞是文件的属性还是read函数的属性?
文件的属性
a、普通文件:hello.c
默认不阻塞
b、终端设备:/dev/tty、管道、套接字
默认阻塞
7、stat函数
(1)函数原型:int stat(const char *pathname,struct stat *buf);
struct stat{
dev_t st_dev;
ino_t st_ino;
mode_t st_mode; //文件的类型和存取的权限
nlink_t st_nlink;
uid_t st_uid; //用户ID
gid_t st_gid; //组ID
dev_t st_rdev;
off_t st_size; //文件字节数(文件大小)
blksize_t st_blksize;
blkcnt_t st_blocks;
time_t st_atime;
time_t st_mtime; //最后一次修改时间
time_t st_ctime;
}
(2)st_mode获取文件类型和权限
在这里插入图片描述
0-2 bit --其他用户权限
3-5 bit --所属组权限
S_IRGRP 00040 读权限
S_IWGRP 00020 写权限
S_IXGRP 00010 执行权限
S_IXGRP 00070 掩码,过滤st_mode中除所属组权限以外的信息
6-8 bit --文件所有者权限
S_IRUSR 00400 读权限
S_IWUSR 00200 写权限
S_IXUSR 00100 执行权限
S_IRWXU 00700 掩码,过滤st_mode中除文件所有者权限以外的信息
12-15 bit --文件类型
S_IFSOCK 0140000 套接字
S_IFLNK 0120000 符号链接(软链接)
S_IFREG 0100000 普通文件
S_IFBLK 0060000 块设备
S_IFDIR 0040000 目录
S_IFCHR 0020000 字符设备
S_IFIFO 0010000 管道

		S_IFMT	0170000掩码,过滤st_mode中除文件类型以外的信息
		使用:
			(st_mode & S_IFMT) == S_IFREG		//判断该文件是否为普通文件

8、lstat和stat函数的区别
(1)lstat读取的链接文件本身的属性
(2)stat读取的是链接文件指向的文件的属性
- 追踪,穿透

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>

int main(int argc,const char* argv[])
{
        struct stat st;
        int ret = lstat("s.s",&st);
        if(ret == -1)
        {
                perror("stat error");
                exit(1);
        }
        printf("file size = %d\n",(int)st.st_size);
        if((S_IFMT & st.st_mode) == S_IFREG)
        {
                printf("this is a regular file\n");
        }
        if(st.st_mode & S_IRUSR)
        {
                printf("        R");
        }
        if(st.st_mode & S_IWUSR)
        {
                printf("        W");
        }
        if(st.st_mode & S_IXUSR)
        {
                printf("        X");
        }
        return 0;
}

9、文件属性相关函数
(1)测试当前用户指定文件是否具有某种属性
int access(const char *pathname,int mode);
pathname:文件名
mode:4种权限
R_OK – 读
W_OK – 写
X_OK – 执行
F_OK – 文件是否存在
返回值:
0 - 有某种权限,或者文件存在
-1 - 没有,或文件不存在
(2)修改文件权限
int chmod(const char *filename,int mode);
filename:文件名
mode:文件权限,八进制数
(3)修改文件所有者和所属组
int chmod(const char *filename,int mode);

附录:部分常用命令

1、查看静态库内容
nm libtest.a
2、查看文件详细信息
file xxx
3、查看可执行程序执行的时候需要链接哪些库
ldd
4、查看系统所有环境变量
env
5、输出PATH的值
echo $PATH
6、环境变量的拼接
:+新路径
7、家目录路径
~/
8、显示当前目录下文件的详细信息
ll
9、修改以太网ip地址
vim /etc/network/interfaces
添加:
auto eth0
iface eth0 inet static
address 192.168.1.111
netmask 255.255.255.0
gateway 192.168.1.1
10、重启网络
sudo /etc/init.d/networking restart
11、查看当前空闲网卡
ip add
12、vim多行注释和取消注释
在这里插入图片描述
13、文件权限
r:4 读
w:2 写
x:1 执行(运行)
-:对应数值0
数字 4 、2 和 1表示读、写、执行权限
rwx = 4 + 2 + 1 = 7 (可读写运行)
rw = 4 + 2 = 6 (可读写不可运行)
rx = 4 +1 = 5 (可读可运行不可写)
14、修改文件权限和所有者和所在组
chmod u+w 文件名(用户权限增加可写)
chmod u-w 文件名(用户权限减少可写)
chmod 777 文件名 -R
chown 用户名 文件名 -R
chgrp 组名 文件名 -R
注:-R表示递归目录下所有文件
15、查看文件内容:
cat 文件名
16、软链接(相当于windows的快捷方式)
ln -s 源文件 目标文件

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值