Linux环境编程

Linux环境编程

程序员必备技能:

一门编译语言 C语言 C++

数据结构与算法 表、树、图 查找、排序 STL

操作系统 Linux系统

网络编程 TCP/IP(Scoket、TCP、UDP、FTP、HTTP)

数据库 MySQL

界面设计 Qt

UNIX系统介绍:

BCPL->newB->C->UNIX

最早版本的UNIX诞生于1970年的贝尔实验室,作者丹尼斯.里奇,肯.汤普逊。

是最早的多用户、多任务、支持多种CPU处理器架构,高安全性、高可靠性、高稳定性的系统

既能架构大型关键性的商用服务器,也能支持移动、嵌入式设备

Minix基于微内核架构的类UNIX操作系统,由此Linux之父林纳斯.托瓦兹受到启发,才开发了第一个版本的Linux。

Linux系统介绍:

**Linux:**全称GNU/Linux,是一种免费使用和自由传播的类UNIX操作系统,其内核由林纳斯·托瓦兹于1991年10月5日首次发布,是一个基于POSIX( 可移植操作系统接口 )的多用户、多任务、支持多线程和多CPU的操作系统。

Linux继承了Unix以网络为核心的设计思想,是一个性能稳定的多用户网络操作系统。

相关知识:

**Linux标志:**企鹅,因为企鹅是南极的标准性动物,而且南极没有被任意国家占领,是属于全人类的。

**GNU组织:**通用的非商业的类UNIX系统,是目前全球最大的开源组织,由该组织负责Linux内核的维护升级

**GPL通用许可证:**在带GPL证书的代码的基础上开发出来的软件,也必须支持GPL通用许可证

**POSIX:**统一的操作系统接口规范,UNIX和Linux都遵循这个标准,因此他们的命令、API接口基本都是通用的

**发行版:**Linux只是内核,内核+Shell(命令解释器)+基础软件才是可以用的操作系统,其他的公司就可以根据Linux内核来设计制作出来不同版本的Linux系统,这就是Linux的发行版。

Ubuntu、RedHat、Debian、CentOS、UOS

GNU编译工具:

**多样化:**支持各种编程语言,支持各种操作系统

gcc -v 查看版本信息

编译过程

​ 预处理: gcc -E code.c code.i

​ 编译: gcc -S code.i ->code.s(汇编文件)

​ 汇编: gcc -c code.s ->code.o(二进制文件)

​ 链接: gcc a.o b.o c.o… ->a.out(执行文件)

文件类型:

.h 头文件

.h.gch 头文件的编译结果

.c 源文件

.i 预处理文件

.s 汇编文件

.o 目标文件(二进制文件)

.a 静态库文件

.so 动态库文件

编译参数:

-E 只预处理
-S 编译处理
-c 汇编
-o 指定编译结果的名字
-g 设置生成调试信息
-std 设置编译语法标准
-Wall 尽可能多的产生警告
-Werror 将警告当做错误处理
-L 设置库文件的加载路径
-I(大写的i) 设置头文件的查找路径
-l(小写的L) 指定要加载的库文件的名字 -lm
-On 优化等级1、2、3
-pedantic 对于不符合 ANSI/ISO 语法标准的代码产生警告
-D 设置宏

预处理指令:

#include <> / “” 头文件包含

#define 定义宏常量、宏函数

​ # 把标识符转换成字符转

​ ## 连接两个标识符

#ifndef 宏名不存在条件为真

#ifdef 宏名存在时条件为真

#undef 删除宏

#if #elif #else #endif 条件判断

#error 直接提示错误 ,并且阻止生成可执行文件(一般配合条件判断使用)

#warning 提示警告

#line 用于设置行号,可以影响下面错误、警告、正常语句

#pragma pack n(1/2/4) 设置对齐、补齐的最大字节数

#pragma once 相当于头文件卫士

#pragma GCC dependency “file.c” 监控文件

#pragma GCC poison xxx “毒药”,设置xxx关键词为"毒药",相当于禁止在代码中使用

库:

​ 库文件就是目的文件的集合,可以被其他代码调整,把代码封装成库文件后方便使用、方便管理、安全性高、保密性高

静态库:

​ 就是目标文件的集合,调用静态库文件就是把静态库中的二进制指令拷贝到可执行文件中

优点:运行速度相对于共享库较快,可执行文件运行时需要静态库的依赖

缺点:可执行文件相对较大,当静态库修改后,可执行文件需要重新编译

共享库:

​ 就是没有入口的可执行文件的集合,调用共享库时就是记录共享库二进制的指针即可。当执行可执行文件时,共享库就要一并加载到内存中,可执行文件就可以跳转到共享库中运行

优点:可执行文件相对较小,当共享库文件修改后,可执行文件不需要重新编译

缺点:运行速度比静态库满,可执行文件运行时也需依赖共享库

静态库:.a

制作静态库:

​ 1、编译文件

gcc -c code.c

​ 2、打包目标文件生成静态库

ar -r/-rv(显示生成过程) libname.a a.o b.o c.o...
例:ar -r libqa.a list_queue.o -o

使用静态库:

​ 1、直接使用

gcc code.c libname.a
例:gcc liba_test.c libqa.a

​ 2、指定库文件的位置(name是静态库文件名去掉前缀和后缀)

gcc code.c -Lpath -lname 
例:gcc liba_test.c -L./lib -qa -std=gnu99

​ 3、通过设置环境变量来指定库的位置(绝对路径)

//打开系统的配置文件
vim ~/.bashrc
//在文件末尾添加库的路径
export LIBRARY_PATH=$LIBRARY_PATH:path
//保存并退出后重新加载
source ~/.bashrc
//使用静态库
gcc code.c -lname【-l:指定库名】
//注意:删除环境变量,需要关闭终端,重启打开才生效

共享库:.so

制作共享库:

​ 1、编译生成目标文件

gcc -fpic -c code.c

-fpic 位置无关
例:gcc -fpic -c list_queue.c

​ 2、生成共享库

gcc -shared -fpic a.o b.o... -o  libname.so
例:gcc -shared -fpic list_queue.o -o libqso.so

使用共享库:

​ 1、使用共享库

//共享库默认打开的地址是系统的lib,所有在自己写好共享库之后,需要将它添加到系统的lib中
gcc code.c libname.so
./a.out		//加载失败,原因是系统只会去默认的共享库中
例: gcc liba_test.c libqso.so -std=gnu99    

​ 2、指定库文件的路径

gcc code.c -Lpath -lname
//注意:如果默认路径没有该共享文件时,执行可执行文件时还是会找不到
例:

​ 3、通过设置环境变量来指定库文件的路径

//打开系统的配置文件
vim ~/.bashrc
//在文件末尾添加库的路径
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:path
//保存并退出后重新加载
source ~/.bashrc
//使用静态库
gcc code.c -lname【-l:指定库名】

注意 当共享库与静态库同名同时存在时,编译器会优先使用共享库,加上 -static 编译参数就可以优先使用静态库

动态加载共享库

#include 

void *dlopen(const char *filename, int flag);
功能:打开共享库
filename:共享库名字
flag:
    RTLD_LAZY	延时加载
    RTLD_NOW	立即加载

char *dlerror(void);
功能:获取错误信息
返回值:返回错误信息的字符串

void *dlsym(void *handle, const char *symbol);
功能:从共享库中获取函数指针
handle:共享库的句柄,也就是dlopen的返回值
symbol:函数名
返回值:成功返回函数的地址,失败返回NULL

int dlclose(void *handle);
功能:关闭共享库
返回值:成功返回0,失败返回-1

注意:使用动态加载共享库的好处:可以在编译时不依赖共享库,只需要在编译时加 -ldl 库,但是在加载共享库时还是需要依赖共享库

静态库和共享库的辅助工具

ldd 查看可执行文件程序依赖哪些共享库

nm 查看目标文件、可执行文件、静态库、共享库的符号列标配

strip 减肥,删除目标文件、可执行文件、静态库、共享库的符号,可以减小文件的大小

objdump 显示目标文件、可执行文件、静态库、共享库的反汇编信息

环境变量表

每个程序执行时,操作系统都会给一个环境变量表,该表中记录了操作系统的所有环境变量,这些环境变量反映了操作系统的配置,以及该程序所处于的系统环境是怎样的。

声明 extern char** environ

操作环境变量表的函数:

#include 

char *getenv(const char *name);
功能:获取环境变量的值

#include 

int setenv(const char *name, const char *value, int overwrite);
功能:向环境变量表中添加环境变量
name:环境变量名
value:环境变量的值
overwrite:当环境变量已经存在时
    为真时:修改原来环境变量的值
    为假时:不修改
    
int putenv(char *string);
功能:以name = value 形式添加修改环境变量,如果存在则修改,不存在则添加
返回值:成功返回0 失败返回-1(操作系统出问题)
    
int unsetenv(const char *name)
功能:删除环境变量
返回值:成功0 失败-1
    
int clearenv(void)
功能:清空环境变量

练习1:

1、添加环境变量 HOME=/home/用户名

2、删除环境变量 LIBRARY_PATH

3、给LD_LIBRARY_PATH的环境变量追加一个路径,主用户目录路径,例:LD_LIBRARY_PATH:/hehe/xixi

​ 追加后:LD_LIBRARY_PATH:/hehe/xixi:/home/用户名

#include
#include
#include

int main(int argc,const char* argv[])
{
    //  1、
    putenv("HOME=/home/用户名");
    printf("%s\n",getenv("HOME"));
    //	2、
    printf("%s\n",getenv("LIBRARY_PATH"));
    unsetenv("LIBRARY_PATH");
    printf("%s\n",getenv("LIBRARY_PATH"));
	//	3、
    char buf[256] = {}; 
    strcpy(buf,getenv("LD_LIBRARY_PATH"));
    strcat(buf,":/home/ubuntu");
    setenv("LD_LIBRARY_PATH",buf,1);
    printf("%s\n",getenv("LD_LIBRARY_PATH"));
    return 0;
}

错误处理

1、通过函数的返回值来表示错误

a、合法值表示成功,非法制表示失败

​ 例如:计算大小、查找

b、指针类型的返回值返回NULL或者0xFFFFFFFF表示失败,其他的都是成功

​ 例如:malloc nmap

c、返回0表示成功,-1表示失败,一般都是系统函数

d、永远成功 printf

2、影响全局的错误编号 errno

定义在errno.h的文件中

#include
char *strerror(int errnum)
功能:根据错误编号来获取详细错误原因,记录到日志中,或者通过网络发送
 
perror("func name") 可以直接显示错误原因

注意:errno是一个全局变量,不能仅仅通过让的值就判断产生错误

练习2:

1、实现一个函数计算文件的大小

2、实现一个字符串子串查找函数

​ 如果找到了,则返回子串第一次出现的位置,如果找不到返回NULL

3、实现计算平均值的函数,考虑求和溢出,该函数不会失败

float avg (int n1,int n2);

#include
#include

//	计算文件的大小
int file_size(const char* path)
{
	FILE* frp = fopen("./1.txt","r");
	if(NULL == frp) return 1;

	fseek(frp,0,SEEK_END);
	int size = ftell(frp);
	return size;
}

//	匹配字符
char* match(const char* str1,const char* str2)
{
	char* tr;
	tr = strstr(str1,str2);
	return tr;
}

//	平均值,且不溢出
float avg(int n1,int n2)
{
	float tmp = n1*1.0/2 + n2*1.0/2;
	return tmp;
}

int main(int argc,const char* argv[])
{
	//--1
	printf("size:%d\n",file_size(".txt"));

	//--2
	char str1[200] ="abcdefg";
	char str2[200] = "dc";
	char* pi = match(str1,str2);
	if(pi != NULL)
		printf("%s\n",pi);
	else
		printf("no match!");
	
	//--3
	float r=0;
	int n1=2147483648, n2=2147483647;
	r = avg(n1,n2);
	printf("%0.2lf",r);
	return 0;
}

你可能感兴趣的:(基础,linux)