上海网站的优化,宁波网络公司哪家最好,程序员参与洗钱网站建设,上海网站建设怎么弄✨个人主页#xff1a; 熬夜学编程的小林
#x1f497;系列专栏#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】
目录 1、静态库
1.1、怎么做静态库
1.2、怎么使用静态库 1、静态库
1.1、怎么做静态库 在Linux环境下#xff0c;通常使用GCC 熬夜学编程的小林
系列专栏 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】
目录 1、静态库
1.1、怎么做静态库
1.2、怎么使用静态库 1、静态库
1.1、怎么做静态库 在Linux环境下通常使用GCCGNU Compiler Collection编译器来编译源代码并使用ararchiver工具来创建静态库。 编写源代码首先你需要有一些源代码文件比如 x.c y.c z.c 编译源代码为对象文件使用GCC编译器将源代码编译为目标文件.o文件。 创建静态库使用 ar工具将对象文件打包成静态库。 头文件是一个手册提供函数的声明告诉用户怎么用.o提供实现我们只需要补上一个main函数调用头文件提供的方法然后和.o进行链接就能形成可执行。
mymath.h
#pragma once // 防止头文件重复包含#include stdio.hint Add(int x,int y);mymath.c
#include mymath.hint Add(int x,int y)
{return x y;
}mystdio.h
#pragma once #include string.h
#include stdlib.h
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include unistd.h#define LINE_SIZE 1024
#define FLUSH_NOW 1
#define FLUSH_LINE 2
#define FLUSH_FULL 4typedef struct _myFILE
{unsigned int flags;int fileno;// 缓冲区char cache[LINE_SIZE];int cap;// 容量int pos;// 下次写入的位置
}myFILE;myFILE* my_fopen(const char* path,const char* flag);
void my_fflush(myFILE* fp);
ssize_t my_fwrite(myFILE* fp,const char* data,int len);
void my_fclose(myFILE* fp);
mystdio.c
#include mystdio.hmyFILE* my_fopen(const char* path,const char* flag)
{int flag1 0;int iscreate 0;mode_t mode 0666;if(strcmp(flag,r) 0){flag1 O_RDONLY;}else if(strcmp(flag,w) 0){flag1 (O_WRONLY | O_CREAT | O_TRUNC);iscreate 1;}else if(strcmp(flag,a) 0){flag1 (O_WRONLY | O_CREAT | O_APPEND);iscreate 1;}else {}int fd 0;if(iscreate)fd open(path,flag1,mode);else fd open(path,flag1);if(fd 0) return NULL;myFILE* fp (myFILE*)malloc(sizeof(myFILE));if(fp NULL) return NULL;fp-fileno fd;fp-flags FLUSH_LINE;fp-cap LINE_SIZE;fp-pos 0;return fp;
}
void my_fflush(myFILE* fp)
{write(fp-fileno,fp-cache,fp-pos);fp-pos 0;
}
ssize_t my_fwrite(myFILE* fp,const char* data,int len)
{// 写入的本质是拷贝条件允许就刷新memcpy(fp-cache fp-pos ,data,len);// 考虑扩容与越界问题fp-pos len;if((fp-flagsFLUSH_LINE) fp-cache[fp-pos-1] \n){my_fflush(fp);}return len;
}
void my_fclose(myFILE* fp)
{my_fflush(fp);close(fp-fileno);free(fp);
}main.c
#include mymath.h
#include mystdio.h
#include string.h
#include stdio.hint main()
{int a 10;int b 20;printf(%d %d %d\n,a,b,myAdd(a,b));myFILE* fp my_fopen(log.txt,w);if(fp NULL) return 1;const char* message 这是我写的...\n;my_fwrite(fp,message,strlen(message));my_fclose(fp);return 0;
}
编译并执行程序
[jklhost lib]$ gcc main.c mymath.c mystdio.c
[jklhost lib]$ ls
a.out log.txt main.c mymath.c mymath.h mystdio.c mystdio.h
[jklhost lib]$ ./a.out
10 20 30
[jklhost lib]$ cat log.txt
这是我写的...将.c文件(源文件)编译成.o文件(目标文件) [ -c选项告诉GCC只编译和汇编但不链接]
gcc -c mymath.c # 将mymath.c文件编译成.o文件默认编译成mymath.o
gcc -c mystdio.c # 将mystdio.c文件编译成.o文件默认编译成mystdio.o
使用.h 文件和.o 文件编译main.c程序
[jklhost roommate]$ ls
main.c mymath.h mymath.o mystdio.h mystdio.o
[jklhost roommate]$ gcc main.c
/tmp/ccFk2rMI.o: In function main:
main.c:(.text0x21): undefined reference to myAdd
main.c:(.text0x49): undefined reference to my_fopen
main.c:(.text0x84): undefined reference to my_fwrite
main.c:(.text0x90): undefined reference to my_fclose
collect2: error: ld returned 1 exit statusgcc main.c 只编译了main.c文件并没有包含对mymath.o 和 mystdio.h 的链接操作因为main.c 依赖于mymath.h 和 mystdio.h 中声明的函数因此仅编译main.c是不够的。 解决办法一
gcc main.c mymath.o mystdio.o -o myexe将.o文件 和.c文件一起编译链接。 解决办法二 将main.o也编译成.o文件 [jklhost roommate]$ gcc -c main.c
[jklhost roommate]$ ls
main.c main.o mymath.h mymath.o mystdio.h mystdio.o
[jklhost roommate]$ gcc mymath.o mystdio.o main.o -o myexe
[jklhost roommate]$ ls
main.c main.o myexe mymath.h mymath.o mystdio.h mystdio.o
[jklhost roommate]$ ./myexe
10 20 30
[jklhost roommate]$ ls
log.txt main.c main.o myexe mymath.h mymath.o mystdio.h mystdio.o
[jklhost roommate]$ cat log.txt
这是我写的...通过ar指令将所有.o文件打包
ar -rc libmyc.a *.o # 将所有.o文件打包成libmyc.a文件 r(replace) 选项表示替换库中已存在的文件。 c(create) 选项表示创建一个新的库 。 1.2、怎么使用静态库
方式一直接使用打包的文件
为了更好的使用静态库我们把前面打包的文件拷贝到另外的目录进行操作。
cp libmyc.a roommate/ # 将打包的文件拷贝到下级目录下
[jklhost roommate]$ cp ../mymath.h . # 将.h文件拷贝到下级目录
[jklhost roommate]$ cp ../mystdio.h .
[jklhost roommate]$ ls
main.c myexe mymath.h mymath.o mystdio.h mystdio.o直接使用gcc 编译
[jklhost roommate]$ gcc main.c
/tmp/ccuZcLr1.o: In function main:
main.c:(.text0x21): undefined reference to myAdd
main.c:(.text0x49): undefined reference to my_fopen
main.c:(.text0x84): undefined reference to my_fwrite
main.c:(.text0x90): undefined reference to my_fclose
collect2: error: ld returned 1 exit status使用gcc 编译main.c 和 libmyc.a
[jklhost roommate]$ gcc main.c libmyc.a
[jklhost roommate]$ ls
a.out libmyc.a main.c mymath.h mystdio.h
[jklhost roommate]$ ./a.out
10 20 30
[jklhost roommate]$ ls
a.out libmyc.a log.txt main.c mymath.h mystdio.h
[jklhost roommate]$ cat log.txt
这是我写的... 方式二将打包的文件拷贝到系统库中(严重不推荐) 我们可以将自己写的.h头文件写到/usr/bin/目录下。 我们可以将自己打包的方法实现文件写到/usr/bin54/目录下。 查看拷贝的文件
[jklhost roommate]$ ls /usr/include/mymath.h
/usr/include/mymath.h
[jklhost roommate]$ ls /usr/include/mystdio.h
/usr/include/mystdio.h
[jklhost roommate]$ ls /usr/lib64/libmyc.a
/usr/lib64/libmyc.a把上面的两步操作做完之后我们可以直接编译main函数头文件可以使用。 main.c
#include mymath.h
#include mystdio.h
#include stdio.h
#include string.hint main()
{int a 10;int b 20;printf(%d %d %d\n,a,b,myAdd(a,b));myFILE* fp my_fopen(log.txt,w);if(fp NULL) return 1;const char* message 这是我写的...\n;my_fwrite(fp,message,strlen(message));my_fclose(fp);return 0;
} 直接使用gcc编译还是会报错因为该方法的实现是我们自己写的gcc/g不认识所以直接编译会报错。 [jklhost roommate]$ gcc main.c
/tmp/ccZqyRSO.o: In function main:
main.c:(.text0x21): undefined reference to myAdd
main.c:(.text0x49): undefined reference to my_fopen
main.c:(.text0x84): undefined reference to my_fwrite
main.c:(.text0x90): undefined reference to my_fclose
collect2: error: ld returned 1 exit status在gcc编译.c文件之后需要加参数-l libmyc.a且需要去掉lib和.a因此正确的命令是gcc main.c -lmyc (-l后面可以加空格也可以不加空格) [jklhost roommate]$ gcc main.c -lmyc
[jklhost roommate]$ ls
a.out main.c mylib
[jklhost roommate]$ ./a.out
10 20 30
[jklhost roommate]$ ls
a.out log.txt main.c mylib
[jklhost roommate]$ cat log.txt
这是我写的...第二种方式不推荐因此演示完之后最好将拷贝的文件给删除掉。
[jklhost roommate]$ sudo rm /usr/include/mymath.h
[jklhost roommate]$ sudo rm /usr/include/mystdio.h
[jklhost roommate]$ sudo rm /usr/lib64/libmyc.a
[jklhost roommate]$ ls /usr/include/mymath.h
ls: cannot access /usr/include/mymath.h: No such file or directory
[jklhost roommate]$ ls /usr/include/mystdio.h
ls: cannot access /usr/include/mystdio.h: No such file or directory
[jklhost roommate]$ ls /usr/lib64/libmyc.a
ls: cannot access /usr/lib64/libmyc.a: No such file or directory 方式三通过命令链接静态库
[jklhost roommate]$ tree .
.
|-- main.c
-- mylib|-- include| |-- mymath.h| -- mystdio.h-- lib-- libmyc.a3 directories, 4 files
为什么不能直接使用 gcc main.c myc.a? 因为告诉了gcc/g编译器但是没有告诉操作系统 使用静态库在编译其他程序时可以通过-I(指定用户自定义头文件搜索路径) -L指定用户自定义库文件搜索路径和 -l执行确定的第三方库名称去掉前缀lib和后缀.a选项来链接静态库。
[jklhost roommate]$ gcc main.c -I ./mylib/include/ -L ./mylib/lib -lmyc
[jklhost roommate]$ ls
a.out main.c mylib
[jklhost roommate]$ ./a.out
10 20 30
[jklhost roommate]$ ls
a.out log.txt main.c mylib
[jklhost roommate]$ cat log.txt
这是我写的...上面是动态链接的
[jklhost roommate]$ ldd a.outlinux-vdso.so.1 (0x00007ffef6bf9000)libc.so.6 /lib64/libc.so.6 (0x00007f0448055000)/lib64/ld-linux-x86-64.so.2 (0x00007f0448423000) gcc在不使用static选项的时候并且只提供.a只能静态链接当前的.a库其他库正常动态链接因此ldd能够查看动态库。 想要静态链接得加 -static
[jklhost roommate]$ gcc main.c -I ./mylib/include/ -L ./mylib/lib -lmyc -static
[jklhost roommate]$ ls
a.out log.txt main.c mylib
[jklhost roommate]$ ldd a.outnot a dynamic executable
[jklhost roommate]$ file a.out
a.out: ELF 64-bit LSB executable, x86-64, version 1 (GNU/Linux), statically linked, for GNU/Linux 2.6.32, BuildID[sha1]b10e09a9d03b05ebc14934c15a9d8b7071c94c29, not stripped
-static的意义是什么 必须强制添加因为将我们的程序进行静态链接这要求我们链接的任何库都必须提供对应的静态库版本。