可以先看几个 shell 编程找找感觉 , 哈哈
#!/bin/bash sum=0 f1=0 f2=1 #-e 开启echo的转义功能,尾部加\c表示不换行 echo -e "$f1+$f2\c" #使用expr执行加法 sum=`expr $sum + $f1 + $f2` #shell脚本中的for循环 for i in $(seq 3 10) do f3=`expr $f1 + $f2` sum=`expr $sum + $f3` f1=$f2 f2=$f3 echo -e "+$f3\c" done echo -e "=$sum"
#!/bin/bash reverseNum(){ array_len=$# #测试集个数 for num in $* do #请在此处键入您的代码 x=$num #ans="" while [ $x -gt 0 ] do t=$[$x%10] echo -e "$t\c" #ans=$[$ans$t] x=$[$x/10] done echo "" done }
#!/bin/bash #请在此处键入你的代码 # 创建 userdata 目录 if [ -d /home/userdata ] then chmod 754 /home/userdata else mkdir -m 754 /home/userdata fi i=1 temp=/home/userdata/user while [ $i -le 5 ] do if [ -d $temp$i ] then chmod 754 $temp$i else mkdir -m 754 $temp$i fi i=$[$i+1] done
#!/bin/bash read -p "Please input an integer number: " number echo -e "the result of '\c" sum=0 for((i=1;i<=number;i++)) do sum=$[$i+sum] if [ $i -le 3 ] then echo -e "$i+\c" elif [ $i -eq $number ] then echo -e "...$i\c'" fi done echo -e "' is ==> $sum"
[root@hadoop100 ~]$ vim test.c #include <stido.h> int mian() { printf("Hello world"); return 0; } [root@hadoop ~]$ gcc test.c // `gcc`默认使用`a.out`作为可执行文件的名字; [root@hadoop ~]$ ./a.out // ./a.out表示运行当前目录下的a.out命令;
c 语言从程序源代码到二进制执行程序需要经历如下四个步骤:
- 预处理
- 预处理是根据处理指令组装新的 C / C ++ 程序。经过预处理,会产生一个没有宏定义,没有条件编译指令,没有特殊符号的输出文件,这个文件的含义同原本的文件无异,只是内容上有新的不同。
- 编译
- 编译是指将预处理完的文件进行行一系列词法分析、语法分析、语义分析及优化后,产生相应的汇编代码文件。
- 汇编
- 编译是指将处理完的汇编代码文件翻译成机器指令,并生成重定位目标程序的 .o 文件,该文件为二进制文件,字节码是机器指令。
- 连接
- 连接过程是指连接机器一个个目标文件(或许还会有库文件)连接在一起生成完整的可执行程序,这个可执行程序才是我们最后直接执行的文件。
gcc 编译器使用的方法
gcc 命令选项 参数
常用命令选择项如下:
1)-o:指定生成的输出文件名字; 2)-E:仅执行编译预处理; 3)-S:将 C 代码转换成汇编代码 4)-c:仅执行编译和汇编操作,不进行连接操作 5)-I:包含库所在的路径 6)-L:指定库所在的路径 7)-l:指定使用的库(小写)
[root@hadoop ~]$ vim firstExec.c #include <stdio.h> int main() { printf("Hwllo GCC\n"); return 0; } [root@hadoop ~]$ gcc -S first.c [root@hadoop100 ~]$ ls -l first.s [root@hadoop100 ~]$ tail firstExec.s [root@hadoop100 ~]$ gcc firstExec.c -o firstExec
第3关:Linux 之静态库编写
1)相关知识
在实际的软件开发时, 应该遵守一个基本原则:不要重复造轮子。如果某些代码经常要用到,不仅这个项目能使用,而且也能复用到其它项目上,那么就应该把这部分代码从项目中分离出来,将其编译为库文件,供需要的程序调用。
程序库分为两类,分别是静态库和动态库。本关将主要讲解如何生成静态库。
Windows
系统上的静态库是以.lib
为后缀,而Linux
系统上的静态库是以.a
为后缀的特殊的存档。
Linux
系统的标准系统库可在目录 /usr/lib
与 /lib
中找到。比如,在类 Unix
系统中C
语言的数序库一般存储为文件 / usr/lib/libm.a
。该库中函数的原型声明在头文件 /usr/include/math.h
中。
生成静态库
在 Linux
下,我们可以使用 gcc
和 ar
工具制作和使用自己的静态库,具体过程如下:
1. 将源码文件编译成 .o 目标文件; 2. 使用 ar 工具将多个目标打包成 .a 的静态文件;
注意 Linux 系统上默认的静态库名格式为: libxxx.a
,其中 xxx
为生成库的名称。
案例演示1:
编写一个函数 printHello
,其功能为打印 “Hello world" 字符串,将其编译生成名为 Hello
的静态库,可以使用如下命令:
vim printHello.h vim printHello.c gcc -c printHello.c -o printHello.o ar rcs libHello.a printHello.o
- 使用
vim
编写printHello.h
(声明printHello
函数,方便以后被其它程序调用)
#ifndef __PRINTHELLO_H__ #define __PRINTHELLO_H__ #include <stdio.h> void printHello(); #endif
- 使用 vim 编写printHello.c
#include <stdio.h> void printHello() { printf("Hello world\n"); }
使用静态库
静态库的使用方法只需要在编译程序的时候指明要链接的库名称即可,gcc
中有两个参数是关于链接库时所使用的,分别是:-L
和-l
。
- -L:用于告诉gcc要链接的库所在目录;
- -l:用于指明链接的库名称(小写l);
案例演示1:
调用以上案例生成的 printHello
函数,可以使用如下命令:
vim main.c gcc main.c -o exe -L ./ -lHello./exe
- 使用
vim
编写main.
#include "printHello.h" int main() { printHello(); return 0; }
样例代码
vim printHello.h
#ifndef __PRINTHELLO_H__ #define __PRINTHELLO_H__ #include <stdio.h> void printHello(); #endif
vim printHello.c
#include <stdio.h> void printHello() { printf("Hello world\n"); }
gcc -c printHello.c -o printHello.o
ar rcs libHello.a printHello.o
vim main.c
#include "printHello.h" int main() { printHello(); return 0; }
gcc main.c -o exe -L ./ -lHello
./exe
编程要求
本关任务是学会生成和使用静态库。
具体编程要求如下:
- 在当前目录下编写一个简单的函数
int Add(int a, int b)
,其功能为计算输入参数a+b
的结果; - 将Add函数编译生成一个静态库
libAdd.a
,并存放在当前目录下;
测试说明
本关的测试需要用户在右侧的命令行下完成,用户只需将需要完成的命令在右侧命令行下直接操作即可,然后点击评测按钮,平台会自动验证用户是否按照要求去检测结果。
vim Add.h
#include <stdio.h> int Add(int a, int b);
vim Add.c
#include <stdio.h> int Add(int a, int b) { printf("%d\n", a + b); }
gcc -c Add.c -o Add.o
ar rcs libAdd.a Add.o
vim main.c
#include "Add.h" int main() { Add(1, 2); return 0; }
gcc main.c -o out -L ./ -lAdd
./out
第4关:Linux之动态库编写
任务描述
本关任务:学会在Linux
系统上生成C
语言的动态库。
相关知识
上一关学习了如何生成静态库,本关将继续讲解如何生成动态库。
- 静态库与动态库的区别:
静态库 | 动态库 | |
名称 | 命名方式是"libxxx.a",库名前加"lib",后缀用".a","xxx"为静态库名 | 命名方式是"libxxx.so", 库名前加"lib",后缀用".so", "xxx"为动态库名 |
链接时间 | 静态库的代码是在编译过程中被载入程序中 | 动态库在编译的时候并没有被编译进目标代码,而是当你的程序执行到相关函数时才调用该函数库里的相应函数 |
优点 | 在编译后的执行程序不在需要外部的函数库支持,因为所使用的函数都已经被编进去了。 | 动态库的改变并不影响你的程序,所以动态函数库升级比较方便 |
缺点 | 如果所使用的静态库发生更新改变,你的程序必须重新编译 | 因为函数库并没有整合进程序,所以程序的运行环境必须提供相应的库 |
Windows
系统上的 动态库 是以.dll
为后缀,而Linux
系统上的 动态库 是以 .so
为后缀的特殊的存档。
生成动态库
在Linux
下,我们可以使用 gcc
制作和使用动态库,具体制作过程如下:
使用gcc命令加-fPIC参数将源码文件编译成.o目标文件; 使用gcc命令加-shared参数将多个目录文件生成一个动态库文件;
注意Linux
系统上默认的动态库名格式为:libxxx.so
,其中xxx
为生成库的名称。
案例演示1:
编写一个函数printHello
,其功能为打印"Hello world"字符串,将其编译生成名为Hello
的动态库,可以使用如下命令
vim printHello.h vim printHello.c gcc -fPIC -c printHello.c -o printHello.o gcc -shared printHello.o -o libHello.so
- 使用
vim
编写printHello.h
(申明printHello
函数,方便以后被其它程序调用)
#ifndef __PRINTHELLO_H__ #define __PRINTHELLO_H__ #include <stdio.h> void printHello(); #endif
- 使用
vim
编写printHello.c
#include <stdio.h> void printHello() { printf("Hello world\n"); }
使用动态库
动态库的使用方法与静态库使用方式略有不同,除了使用gcc
中的-L
和-l
参数外,想要调用动态库还需要更新Linux
系统中/etc/ld.so.cache
或者修改LD_LIBRARY_PATH
环境变量,否则在运行程序的时候会报**“No such file or directory”**错误。
案例演示1:
调用以上案例生成的printHello
函数,可以使用如下命令:
vim main.c gcc main.c -o exe -L ./ -lHello ./exe
更新/etc/ld.so.cache来运行动态库
- 编辑
/etc/ld.so.conf
配置文件,然后加入需要加载的动态库目录。 - 运行
ldconfig
更新/etc/ld.so.cache
案例演示1:
更新/etc/ld.so.cache
,然后运行上一个案例生成的exe
,可以使用如下命令:
sudo vim /etc/ld.so.conf sudo ldconfig ./exe
修改LD_LIBRARY_PATH
环境变量
在运行可执行文件前修改LD_LIBRARY_PATH
变量为可执行程序指定需要加载的动态库路径。
案例演示1:
修改LD_LIBRARY_PATH
,然后运行上一个案例生成的exe
,可以使用如下命令:
LD_LIBRARY_PATH=. ./exe
注意:
LD_LIBRARY_PATH告诉了exe程序现在当前目录下寻找链接的动态库;
当运行环境中同时存在同名的静态库和动态库时,默认优先链接动态库;
vim printHello.h
#ifndef __PRINTHELLO_H__ #define __PRINTHELLO_H__ #include <stdio.h> void printHello(); #endif
vim printHello.c
#include <stdio.h> { printf("Hello world\n"); }
gcc -fPIC -c printHello.c -o printHello.o
gcc -shared printHello.o -o libHello.so
ls -l libHello.so
[root@hadoop102 样例演示]# ls -l libHello.so -rwxr-xr-x. 1 root root 8120 Sep 3 15:16 libHello.so
vim main.c
// 在这里调用的库必须是用双引号好引起来 #include "printHello.h" int main() { printHello(); return 0; }
gcc main.c -o exe -L ./ -lHello
sudo vim /etc/ld.so.conf
ldconfig
LD_LIBRARY_PATH=. ./exe
./exe
编程要求
本关任务是学会生成和使用动态库。
具体编程要求如下:
- 在当前目录下编写一个简单的函数
int Sub(int a, int b)
,其功能为计算输入参数a-b
的结果; - 将Sub函数编译生成一个动态库
libSub.so
,并存放在当前目录下; - 修改
/etc/ld.so.conf
,添加当前目录,并更新/etc/ld.so.cache
;
测试说明
本关的测试需要用户在右侧的命令行下完成,用户只需将需要完成的命令在右侧命令行下直接操作即可,然
vim Sub.h
#ifndef __PRINTHELLO_H__ #define __PRINTHELLO_H__ #include <stdio.h> int Sub(int a, int b); #endif
vim Sub.c
#include <stdio.h> int Sub(int a, int b) { return a - b; }
gcc -fPIC -c Sub.c -o Sub.o
gcc -shared Sub.o -o libSub.so
vim main.c
#include "Sub.h" int main() { printf("%d\n", Sub(2, 1)); return 0; }
vim /etc/ld.so.conf
ldconfig
gcc main.c -o exe -L ./ -lSub
LD_LIBRARY_PATH=. ./exe
./exe