LinuxAdvancedProgrammingResearch - juedaiyuer/researchNote GitHub Wiki

#Linux高级程序设计#

工具:sourceinsight

Linux下编辑调试工具 gcc gdb

四个步骤

  1. 预处理 去掉注释,进行宏替换(#define相关),头文件(#include)包含
    gcc -E ...

  2. 编译 编译成汇编语言,基于不同的平台,X86,ARM...
    gcc -S ...

  3. 汇编 将汇编语言翻译成二进制的目标代码
    gcc -c ...

  4. 链接 包含各函数库的入口,得到可执行代码
    gcc -o ...

Linux的C源代码文件后缀.c
.C C++
优化:目标是使代码性能更优,去掉冗余代码,工具自动完成,-O 0/1/2/3

gcc -g 生成调试信息

gdb
l是list的意思,列出各行编号
b 行号 设置断点
n是下一步
c是continue 下一个断点
p 变量名 打印这个变量的值

库的使用 系统定义的头文件 /usr/include /usr/local/include /usr/target/include

库文件 /lib
ldd file(可执行文件) 可以列出此文件使用了哪些库文件

math库
编译时默认链接c库,如果要使用其它的库,编译时要用-l

系统限制
limit.h float.h(数据类型限制)
本身限制:资源有限,不可能无限制的申请资源
命令行:ulimit来修改和获取
编程:getrlimit函数来获取,setrlimit来设置系统的限制

RLIMIT_CORE :core文件的最大字节数,core文件是系统某个进程出现异常退出时,系统为其保存的上下文信息,在调试程序时经常要用
RLIMIT_CPU:CPU时间的最大值(s)
RLIMIT_DATA:一个进程数据段的最大字节数
RLIMIT_FSIZE:可创建文件的最大值
RLIMIT_NOFILE:每个进程可以打开的文件的个数
RLIMIT_STACK:进程栈空间的最大值
RLIMIT_VMEN:虚拟地址空间的最大值
RLIMIT_AS:系统进程可用内存空间最大值

##命令行参数##

main函数的参数问题 argc:参数的个数
argv[]:指针数组,存放具体的参数列表

测试代码:

#include<stdio.h>
int main(int argc,char* argv[]){
	int i;
	for(i=0;i<argc;i++)
		printf("argv[%d]=%s\n",i,argv[i]);
	return 0;
}

main函数提取命令行参数列表
getopt
getlongopt

#include<unistd.h>
int getopt(int argc,char* const argv[],const char* optstring);

##内存管理##

###进程地址空间### 可执行文件

查看文件的结构:size file

三个部分

  1. 代码段 主要存放指令,操作,只读常量
  2. 数据段 全局,静态,二者初始化过的
  3. BSS段 未初始化的变量

程序存在磁盘上(读取慢),运行时加载到内存中(读取快,CPU可直接访问读写)
进程:最小的资源管理单元,一个程序运行,必然为其创建一个进程,进程是有生命周期的,一个进程是执行的程序段.当然一个程序也可有创建多个进程.

内核中的资源:
PCB进程控制块,结构体task struct,负责管理进程的所有资源
成员 mm_struct 指向相关的内存资源

  1. 代码段,数据段,BSS段,直接从磁盘拷贝到当前内存空间,大小相等
  2. 动态空间 堆栈,mmap段(映射其它的库的相关信息)

进程所在的目录 /proc
ps -aux | grep file(可执行文件名)

进程的内存地址信息列表

  1. cat /proc/进程id/maps
  2. pmap

地址实际并不是真正的物理地址,而是虚拟地址空间,用于对资源的保护. 内存资源是宝贵的,执行一个程序,并不需要将所有内存资源加载到内存中,采用写时申请技术.

好处

  1. 保护系统,用户程序非法访问不能造成内核崩溃,段错误出现时,非法访问进程自动退出
  2. 节约资源,采用内存映射,一个程序执行时,不是将所有资源都加载到内存中,而是使用缺页真正申请物理空间.

32位平台,一个进程拥有自己的4G的虚拟地址空间

###虚拟地址空间布局###

进程执行时,如何申请内存空间,申请哪些空间

##Posix磁盘文件内容管理##

  • 磁盘文件需要经过系统调用,一个程序(进程)与要操作的文件建立联系
  • 操作磁盘文件,要用到内存做到桥梁作用,系统调用磁盘文件,返回一个文件描述符
  • Linux操作系统提供了open系统调用,任何的进程访问一个文件,需要使用open,返回一个文件描述符
  • 读写文件内容 read/write
  • 文件位置的修改 lseek
  1. 用户程序从用户空间向内核空间提交打开文件申请
  2. 操作系统会在内核中检查请求的合法性,在内核中申请这个打开文件的信息(读写位置,在磁盘中的位置...用struct files来存储).并且添加到当前进程的PCB块中的打开文件列表数组中,对应的这个数组下标即文件描述符
  3. 文件描述符返回用户空间,用户空间进行操作

进程控制块-打开文件列表-文件表项(struct file)

系统认为每个进程打开了三个文件
printf/scanf
文件描述符0(标准输入-键盘 STDIN_FILENO) 1(标准输出-显示器 STDOUT_FILENO) 2(标准错误输出-显示器 STDERR_FILENO)

  • IO系统调用函数
  1. 建立与断开联系 open/close

open

int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
int creat(const char *pathname, mode_t mode);

flag:
只读 O_READONLY
只写 O_WRITEONLY
读写 O_RDWR
追加 O_APPEND

mode
创建新文件的权限
新创建一个文件的真正权限: mode & ~umask

打开文件成功,返回一个新的文件描述符

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

int main(int argc,char* argv[])
{
    int fd;
    fd = open(argv[1],O_RDONLY|O_CREAT,0664);
    if(-1 == fd)
    {
            perror("open");
            exit(EXIT_FAILURE);
    }
    printf("fd:%d\n",fd);
    close(fd);
}
  • 测试程序,功能:打开一个文件返回ID,亦可以创建一个目录下不存在的文件 ./a.out 文件名

简单的拷贝文件实现

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

// cp src -> dst
// argv[1] src
// argv[2] dst
int main(int argc,char* argv[])
{
    if(argc !=3)
    {
            printf("please input message format as :%s src_file dst_file\n",argv[0]);
            exit(EXIT_FAILURE);
    }

    int fd_src,fd_dst;
    fd_src = open(argv[1],O_RDONLY);
    if(-1 == fd_src)
    {
            perror("open");
            exit(EXIT_FAILURE);
    }
    printf("fd_src:%d\n",fd_src);

    fd_dst = open(argv[2],O_WRONLY|O_CREAT,0664);
    if(-1 == fd_dst)
    {
            perror("open");
            exit(EXIT_FAILURE);
    }

    //内存空间,并且初始化
    char buf[1024];
    int ret = 0;
    memset(buf,'\0',1024);

    ret = read(fd_src,buf,1024); //src文件读入内存,返回读入的字节数
    write(fd_dst,buf,ret);

    close(fd_src);
    close(fd_dst);
}
  • 测试程序,文件大小有限制.

  • 文件大小解决办法

    char buf[1024]; int ret = 0;

    while(1) { memset(buf,'\0',1024);

      ret = read(fd_src,buf,1024); //src文件读入内存,返回读入的字节数
    
      if(ret == -1)
      {
              perror("read");
              exit(EXIT_FAILURE);
      }
      else if(ret == 0)
              break;
      else
              write(fd_dst,buf,ret);
    

    }

  • 对当前文件的读写位置进行定位,可以在文件中添加空洞 lseek

  • 文件头 SEEK_SET ----当前读写位置SEEK_CUR ---- 文件尾 SEEK_END ; 偏移

  • 也可以用这个函数来实现文件大小的获取,把文件的读写位置设置为文件结束,因为这个函数返回当前读写位置距离文件头的偏移字节数

文件描述符操作

  • 复制 dup,dup2,fcntl,两个文件描述符指向同一表项

    close(0) dup(3)

  • 这个代码可以实现输入的重定向,默认从0读数据,现在0指向的表被复制为3,这样从0读实际上就是从3指向的文件读,也就实现了输入的重定向

    dup(3,0) // 等效于 close(0) dup(3)

锁定

  • 并发的环境,除了使用并发的工具来保护共享文件外,也可以使用文件锁,flock
  1. LOCK_SH 共享锁
  2. LOCK_EX exclusive lock 排它锁
  3. LOCK_UN
  4. LOCK_NB 非阻塞式申请

如果锁定某一部分,可以使用fcntl函数

属性控制,权限状态,拥有者等

  • fcntl 当前的读写状态,当前文件描述符所在的进程等系列信息

提高效率,同步磁盘

  • mmap函数打开虚拟地址空间,以后操作类似于操作这个文件

##ANSI C文件IO管理##

position : Linux高级程序设计-第四章

  • 流是在文件描述符基础上进行的封装,添加了如下的信息,使功能
  1. 缓冲区
  2. 读写位置

缓冲区

  1. 全缓冲区: /usr/include/stdio.h
    BUFSIZ
  2. 行缓冲区
    换行符,缓冲区满才刷新行缓冲
    部分系统默认128个字节
    终端即行缓冲
  3. 不带缓冲区
    wirte()系统调用函数,标准出错流stderr

IO操作

FILE *fopen(const char *path, const char *mode); //文件流
w      
Truncate  file  to  zero length or create text file for writing.  The stream is positioned at the beginning of the file.
int fclose(FILE *fp);

int fflush(FILE *stream); //更新缓存区内容

//字符读写操作

while(ch = fget(fp)!=EOF);   //按字符输出到标准输出stdout
    fputc(ch,std); 

//行读写文件流

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);

The  function  fread()  reads  nmemb elements of data, each size bytes long, from the stream pointed to by stream, storing them at the location given by ptr.

size_t fwrite(const void *ptr, size_t size, size_t nmemb,FILE *stream);

feof() //判断文件流末尾

文件流定位

  • ftell 返回当前读写位置
  • fseek 修改当前的读写位置
  • rewind 重置读写位置

代码示例

  1. ftell和fseek实现某文件大小-length_example.c
  2. 实现文件复制操作-cp_examlpe.c

流的格式化输入输出

page:108

  • printf/scanf
  • fprintf/fscanf

source:

  1. Linux高级程序设计

课程讲师的网页地址

守望者

pos: title:Linux高级程序设计(evernote)

⚠️ **GitHub.com Fallback** ⚠️